Search in sources :

Example 21 with DeckDueTreeNode

use of com.ichi2.libanki.sched.DeckDueTreeNode in project Anki-Android by ankidroid.

the class SchedTest method test_deckDueV1.

@Test
public void test_deckDueV1() throws Exception {
    Collection col = getColV1();
    // add a note with default deck
    Note note = col.newNote();
    note.setItem("Front", "one");
    col.addNote(note);
    // and one that's a child
    note = col.newNote();
    note.setItem("Front", "two");
    long default1 = addDeck("Default::1");
    note.model().put("did", default1);
    col.addNote(note);
    // make it a review card
    Card c = note.cards().get(0);
    c.setQueue(QUEUE_TYPE_REV);
    c.setDue(0);
    c.flush();
    // add one more with a new deck
    note = col.newNote();
    note.setItem("Front", "two");
    JSONObject foobar = note.model().put("did", addDeck("foo::bar"));
    col.addNote(note);
    // and one that's a sibling
    note = col.newNote();
    note.setItem("Front", "three");
    JSONObject foobaz = note.model().put("did", addDeck("foo::baz"));
    col.addNote(note);
    col.reset();
    assertEquals(5, col.getDecks().allSortedNames().size());
    DeckDueTreeNode tree = col.getSched().deckDueTree().get(0);
    assertEquals("Default", tree.getLastDeckNameComponent());
    // sum of child and parent
    assertEquals(1, tree.getDid());
    assertEquals(1, tree.getRevCount());
    assertEquals(1, tree.getNewCount());
    // child count is just review
    DeckDueTreeNode child = tree.getChildren().get(0);
    assertEquals("1", child.getLastDeckNameComponent());
    assertEquals(default1, child.getDid());
    assertEquals(1, child.getRevCount());
    assertEquals(0, child.getNewCount());
    // code should not fail if a card has an invalid deck
    c.setDid(12345);
    c.flush();
    col.getSched().deckDueTree();
}
Also used : JSONObject(com.ichi2.utils.JSONObject) Note(com.ichi2.libanki.Note) Collection(com.ichi2.libanki.Collection) Card(com.ichi2.libanki.Card) RobolectricTest(com.ichi2.anki.RobolectricTest) Test(org.junit.Test)

Example 22 with DeckDueTreeNode

use of com.ichi2.libanki.sched.DeckDueTreeNode in project Anki-Android by ankidroid.

the class SchedTest method ensureDeckTree.

@Test
public void ensureDeckTree() {
    for (String deckName : TEST_DECKS) {
        addDeck(deckName);
    }
    getCol().getSched().deckDueTree();
    AbstractSched sched = getCol().getSched();
    List<DeckDueTreeNode> tree = sched.deckDueTree();
    Assert.assertEquals("Tree has not the expected structure", SchedV2Test.expectedTree(getCol(), false), tree);
}
Also used : Matchers.containsString(org.hamcrest.Matchers.containsString) RobolectricTest(com.ichi2.anki.RobolectricTest) Test(org.junit.Test)

Example 23 with DeckDueTreeNode

use of com.ichi2.libanki.sched.DeckDueTreeNode in project Anki-Android by ankidroid.

the class Sched method deckDueList.

/*
      Deck list **************************************************************** *******************************
     */
/**
 * Returns [deckname, did, rev, lrn, new]
 */
@Override
@Nullable
public List<DeckDueTreeNode> deckDueList(@Nullable CancelListener cancelListener) {
    _checkDay();
    mCol.getDecks().checkIntegrity();
    List<Deck> decks = mCol.getDecks().allSorted();
    HashMap<String, Integer[]> lims = HashUtil.HashMapInit(decks.size());
    ArrayList<DeckDueTreeNode> deckNodes = new ArrayList<>(decks.size());
    for (Deck deck : decks) {
        if (isCancelled(cancelListener)) {
            return null;
        }
        String deckName = deck.getString("name");
        String p = Decks.parent(deckName);
        // new
        int nlim = _deckNewLimitSingle(deck, false);
        int rlim = _deckRevLimitSingle(deck, false);
        if (!TextUtils.isEmpty(p)) {
            Integer[] parentLims = lims.get(Decks.normalizeName(p));
            // 'temporary for diagnosis of bug #6383'
            Assert.that(parentLims != null, "Deck %s is supposed to have parent %s. It has not be found.", deckName, p);
            nlim = Math.min(nlim, parentLims[0]);
            // review
            rlim = Math.min(rlim, parentLims[1]);
        }
        int _new = _newForDeck(deck.getLong("id"), nlim);
        // learning
        int lrn = _lrnForDeck(deck.getLong("id"));
        // reviews
        int rev = _revForDeck(deck.getLong("id"), rlim);
        // save to list
        deckNodes.add(new DeckDueTreeNode(mCol, deck.getString("name"), deck.getLong("id"), rev, lrn, _new));
        // add deck as a parent
        lims.put(Decks.normalizeName(deck.getString("name")), new Integer[] { nlim, rlim });
    }
    return deckNodes;
}
Also used : ArrayList(java.util.ArrayList) Deck(com.ichi2.libanki.Deck) Nullable(androidx.annotation.Nullable)

Example 24 with DeckDueTreeNode

use of com.ichi2.libanki.sched.DeckDueTreeNode in project Anki-Android by ankidroid.

the class SchedV2 method deckDueList.

// Overridden
@Nullable
public List<DeckDueTreeNode> deckDueList(@Nullable CancelListener collectionTask) {
    _checkDay();
    mCol.getDecks().checkIntegrity();
    List<Deck> decks = mCol.getDecks().allSorted();
    HashMap<String, Integer[]> lims = HashUtil.HashMapInit(decks.size());
    ArrayList<DeckDueTreeNode> deckNodes = new ArrayList<>(decks.size());
    Decks.Node childMap = mCol.getDecks().childMap();
    for (Deck deck : decks) {
        if (isCancelled(collectionTask)) {
            return null;
        }
        String deckName = deck.getString("name");
        String p = Decks.parent(deckName);
        // new
        int nlim = _deckNewLimitSingle(deck, false);
        Integer plim = null;
        if (!TextUtils.isEmpty(p)) {
            Integer[] parentLims = lims.get(Decks.normalizeName(p));
            // 'temporary for diagnosis of bug #6383'
            Assert.that(parentLims != null, "Deck %s is supposed to have parent %s. It has not be found.", deckName, p);
            nlim = Math.min(nlim, parentLims[0]);
            // reviews
            plim = parentLims[1];
        }
        int _new = _newForDeck(deck.getLong("id"), nlim);
        // learning
        int lrn = _lrnForDeck(deck.getLong("id"));
        // reviews
        int rlim = _deckRevLimitSingle(deck, plim, false);
        int rev = _revForDeck(deck.getLong("id"), rlim, childMap);
        // save to list
        deckNodes.add(new DeckDueTreeNode(mCol, deck.getString("name"), deck.getLong("id"), rev, lrn, _new));
        // add deck as a parent
        lims.put(Decks.normalizeName(deck.getString("name")), new Integer[] { nlim, rlim });
    }
    return deckNodes;
}
Also used : Decks(com.ichi2.libanki.Decks) ArrayList(java.util.ArrayList) Deck(com.ichi2.libanki.Deck) Nullable(androidx.annotation.Nullable)

Example 25 with DeckDueTreeNode

use of com.ichi2.libanki.sched.DeckDueTreeNode in project Anki-Android by ankidroid.

the class CardContentProvider method query.

@Override
public Cursor query(@NonNull Uri uri, String[] projection, String selection, String[] selectionArgs, String order) {
    if (!hasReadWritePermission() && shouldEnforceQueryOrInsertSecurity()) {
        throwSecurityException("query", uri);
    }
    Collection col = CollectionHelper.getInstance().getCol(mContext);
    if (col == null) {
        throw new IllegalStateException(COL_NULL_ERROR_MSG);
    }
    Timber.d(getLogMessage("query", uri));
    // Find out what data the user is requesting
    int match = sUriMatcher.match(uri);
    switch(match) {
        case NOTES_V2:
            {
                /* Search for notes using direct SQL query */
                String[] proj = sanitizeNoteProjection(projection);
                String sql = SQLiteQueryBuilder.buildQueryString(false, "notes", proj, selection, null, null, order, null);
                // Needed for varargs of query
                return col.getDb().query(sql, (Object[]) selectionArgs);
            }
        case NOTES:
            {
                /* Search for notes using the libanki browser syntax */
                String[] proj = sanitizeNoteProjection(projection);
                String query = (selection != null) ? selection : "";
                List<Long> noteIds = col.findNotes(query);
                if ((noteIds != null) && (!noteIds.isEmpty())) {
                    String sel = String.format("id in (%s)", TextUtils.join(",", noteIds));
                    String sql = SQLiteQueryBuilder.buildQueryString(false, "notes", proj, sel, null, null, order, null);
                    return col.getDb().getDatabase().query(sql);
                } else {
                    return null;
                }
            }
        case NOTES_ID:
            {
                /* Direct access note with specific ID*/
                String noteId = uri.getPathSegments().get(1);
                String[] proj = sanitizeNoteProjection(projection);
                String sql = SQLiteQueryBuilder.buildQueryString(false, "notes", proj, "id=?", null, null, order, null);
                return col.getDb().query(sql, noteId);
            }
        case NOTES_ID_CARDS:
            {
                Note currentNote = getNoteFromUri(uri, col);
                String[] columns = ((projection != null) ? projection : FlashCardsContract.Card.DEFAULT_PROJECTION);
                MatrixCursor rv = new MatrixCursor(columns, 1);
                for (Card currentCard : currentNote.cards()) {
                    addCardToCursor(currentCard, rv, col, columns);
                }
                return rv;
            }
        case NOTES_ID_CARDS_ORD:
            {
                Card currentCard = getCardFromUri(uri, col);
                String[] columns = ((projection != null) ? projection : FlashCardsContract.Card.DEFAULT_PROJECTION);
                MatrixCursor rv = new MatrixCursor(columns, 1);
                addCardToCursor(currentCard, rv, col, columns);
                return rv;
            }
        case MODELS:
            {
                ModelManager models = col.getModels();
                String[] columns = ((projection != null) ? projection : FlashCardsContract.Model.DEFAULT_PROJECTION);
                MatrixCursor rv = new MatrixCursor(columns, 1);
                for (Long modelId : models.getModels().keySet()) {
                    addModelToCursor(modelId, models, rv, columns);
                }
                return rv;
            }
        case MODELS_ID:
            {
                long modelId = getModelIdFromUri(uri, col);
                String[] columns = ((projection != null) ? projection : FlashCardsContract.Model.DEFAULT_PROJECTION);
                MatrixCursor rv = new MatrixCursor(columns, 1);
                addModelToCursor(modelId, col.getModels(), rv, columns);
                return rv;
            }
        case MODELS_ID_TEMPLATES:
            {
                /* Direct access model templates */
                ModelManager models = col.getModels();
                Model currentModel = models.get(getModelIdFromUri(uri, col));
                String[] columns = ((projection != null) ? projection : CardTemplate.DEFAULT_PROJECTION);
                MatrixCursor rv = new MatrixCursor(columns, 1);
                try {
                    JSONArray templates = currentModel.getJSONArray("tmpls");
                    for (int idx = 0; idx < templates.length(); idx++) {
                        JSONObject template = templates.getJSONObject(idx);
                        addTemplateToCursor(template, currentModel, idx + 1, models, rv, columns);
                    }
                } catch (JSONException e) {
                    throw new IllegalArgumentException("Model is malformed", e);
                }
                return rv;
            }
        case MODELS_ID_TEMPLATES_ID:
            {
                /* Direct access model template with specific ID */
                ModelManager models = col.getModels();
                int ord = Integer.parseInt(uri.getLastPathSegment());
                Model currentModel = models.get(getModelIdFromUri(uri, col));
                String[] columns = ((projection != null) ? projection : CardTemplate.DEFAULT_PROJECTION);
                MatrixCursor rv = new MatrixCursor(columns, 1);
                try {
                    JSONObject template = getTemplateFromUri(uri, col);
                    addTemplateToCursor(template, currentModel, ord + 1, models, rv, columns);
                } catch (JSONException e) {
                    throw new IllegalArgumentException("Model is malformed", e);
                }
                return rv;
            }
        case SCHEDULE:
            {
                String[] columns = ((projection != null) ? projection : FlashCardsContract.ReviewInfo.DEFAULT_PROJECTION);
                MatrixCursor rv = new MatrixCursor(columns, 1);
                long selectedDeckBeforeQuery = col.getDecks().selected();
                long deckIdOfTemporarilySelectedDeck = -1;
                // the number of scheduled cards to return
                int limit = 1;
                int selectionArgIndex = 0;
                // parsing the selection arguments
                if (selection != null) {
                    // split selection to get arguments like "limit=?"
                    String[] args = selection.split(",");
                    for (String arg : args) {
                        // split arguments into key ("limit") and value ("?")
                        String[] keyAndValue = arg.split("=");
                        try {
                            // check if value is a placeholder ("?"), if so replace with the next value of selectionArgs
                            String value = "?".equals(keyAndValue[1].trim()) ? selectionArgs[selectionArgIndex++] : keyAndValue[1];
                            if ("limit".equals(keyAndValue[0].trim())) {
                                limit = Integer.parseInt(value);
                            } else if ("deckID".equals(keyAndValue[0].trim())) {
                                deckIdOfTemporarilySelectedDeck = Long.parseLong(value);
                                if (!selectDeckWithCheck(col, deckIdOfTemporarilySelectedDeck)) {
                                    // if the provided deckID is wrong, return empty cursor.
                                    return rv;
                                }
                            }
                        } catch (NumberFormatException nfe) {
                            Timber.w(nfe);
                        }
                    }
                }
                // retrieve the number of cards provided by the selection parameter "limit"
                col.getSched().deferReset();
                for (int k = 0; k < limit; k++) {
                    Card currentCard = col.getSched().getCard();
                    if (currentCard == null) {
                        break;
                    }
                    int buttonCount = col.getSched().answerButtons(currentCard);
                    JSONArray buttonTexts = new JSONArray();
                    for (int i = 0; i < buttonCount; i++) {
                        buttonTexts.put(col.getSched().nextIvlStr(mContext, currentCard, i + 1));
                    }
                    addReviewInfoToCursor(currentCard, buttonTexts, buttonCount, rv, col, columns);
                }
                if (deckIdOfTemporarilySelectedDeck != -1) {
                    // if the selected deck was changed
                    // change the selected deck back to the one it was before the query
                    col.getDecks().select(selectedDeckBeforeQuery);
                }
                return rv;
            }
        case DECKS:
            {
                List<DeckDueTreeNode> allDecks = col.getSched().deckDueList();
                String[] columns = ((projection != null) ? projection : FlashCardsContract.Deck.DEFAULT_PROJECTION);
                MatrixCursor rv = new MatrixCursor(columns, allDecks.size());
                for (DeckDueTreeNode deck : allDecks) {
                    long id = deck.getDid();
                    String name = deck.getFullDeckName();
                    addDeckToCursor(id, name, getDeckCountsFromDueTreeNode(deck), rv, col, columns);
                }
                return rv;
            }
        case DECKS_ID:
            {
                /* Direct access deck */
                String[] columns = ((projection != null) ? projection : FlashCardsContract.Deck.DEFAULT_PROJECTION);
                MatrixCursor rv = new MatrixCursor(columns, 1);
                List<DeckDueTreeNode> allDecks = col.getSched().deckDueList();
                long deckId = Long.parseLong(uri.getPathSegments().get(1));
                for (DeckDueTreeNode deck : allDecks) {
                    if (deck.getDid() == deckId) {
                        addDeckToCursor(deckId, deck.getFullDeckName(), getDeckCountsFromDueTreeNode(deck), rv, col, columns);
                        return rv;
                    }
                }
                return rv;
            }
        case DECK_SELECTED:
            {
                long id = col.getDecks().selected();
                String name = col.getDecks().name(id);
                String[] columns = ((projection != null) ? projection : FlashCardsContract.Deck.DEFAULT_PROJECTION);
                MatrixCursor rv = new MatrixCursor(columns, 1);
                JSONArray counts = new JSONArray(Collections.singletonList(col.getSched().counts()));
                addDeckToCursor(id, name, counts, rv, col, columns);
                return rv;
            }
        default:
            // Unknown URI type
            throw new IllegalArgumentException("uri " + uri + " is not supported");
    }
}
Also used : JSONArray(com.ichi2.utils.JSONArray) JSONException(com.ichi2.utils.JSONException) ModelManager(com.ichi2.libanki.ModelManager) MatrixCursor(android.database.MatrixCursor) Card(com.ichi2.libanki.Card) DeckDueTreeNode(com.ichi2.libanki.sched.DeckDueTreeNode) JSONObject(com.ichi2.utils.JSONObject) Note(com.ichi2.libanki.Note) Model(com.ichi2.libanki.Model) Collection(com.ichi2.libanki.Collection) List(java.util.List) ArrayList(java.util.ArrayList)

Aggregations

RobolectricTest (com.ichi2.anki.RobolectricTest)13 Test (org.junit.Test)13 Collection (com.ichi2.libanki.Collection)11 ArrayList (java.util.ArrayList)9 Card (com.ichi2.libanki.Card)8 Note (com.ichi2.libanki.Note)8 DeckDueTreeNode (com.ichi2.libanki.sched.DeckDueTreeNode)7 Deck (com.ichi2.libanki.Deck)6 JSONObject (com.ichi2.utils.JSONObject)6 Matchers.containsString (org.hamcrest.Matchers.containsString)6 Nullable (androidx.annotation.Nullable)5 Model (com.ichi2.libanki.Model)4 JSONArray (com.ichi2.utils.JSONArray)4 MatrixCursor (android.database.MatrixCursor)2 DeckConfig (com.ichi2.libanki.DeckConfig)2 JSONException (com.ichi2.utils.JSONException)2 HashMap (java.util.HashMap)2 List (java.util.List)2 AlarmManager (android.app.AlarmManager)1 Notification (android.app.Notification)1