Search in sources :

Example 21 with Counts

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

the class SchedV2Test method test_learn_dayV2.

@Test
public void test_learn_dayV2() throws Exception {
    Collection col = getColV2();
    // add a note
    Note note = col.newNote();
    note.setItem("Front", "one");
    col.addNote(note);
    col.reset();
    Card c = getCard();
    DeckConfig conf = col.getSched()._cardConf(c);
    conf.getJSONObject("new").put("delays", new JSONArray(new double[] { 1, 10, 1440, 2880 }));
    col.getDecks().save(conf);
    // pass it
    col.getSched().answerCard(c, BUTTON_THREE);
    // two reps to graduate, 1 more today
    assertEquals(3, c.getLeft() % 1000);
    assertEquals(1, c.getLeft() / 1000);
    assertEquals(new Counts(0, 1, 0), col.getSched().counts());
    c = getCard();
    assertEquals(SECONDS_PER_DAY, col.getSched().nextIvl(c, BUTTON_THREE));
    // answering it will place it in queue 3
    col.getSched().answerCard(c, BUTTON_THREE);
    assertEquals(col.getSched().getToday() + 1, c.getDue());
    assertEquals(QUEUE_TYPE_DAY_LEARN_RELEARN, c.getQueue());
    assertNull(getCard());
    // for testing, move it back a day
    c.setDue(c.getDue() - 1);
    c.flush();
    col.reset();
    assertEquals(new Counts(0, 1, 0), col.getSched().counts());
    c = getCard();
    // nextIvl should work
    assertEquals(SECONDS_PER_DAY * 2, col.getSched().nextIvl(c, BUTTON_THREE));
    // if we fail it, it should be back in the correct queue
    col.getSched().answerCard(c, BUTTON_ONE);
    assertEquals(QUEUE_TYPE_LRN, c.getQueue());
    col.undo();
    col.reset();
    c = getCard();
    col.getSched().answerCard(c, BUTTON_THREE);
    // simulate the passing of another two days
    c.setDue(c.getDue() - 2);
    c.flush();
    col.reset();
    // the last pass should graduate it into a review card
    assertEquals(SECONDS_PER_DAY, col.getSched().nextIvl(c, BUTTON_THREE));
    col.getSched().answerCard(c, BUTTON_THREE);
    assertEquals(CARD_TYPE_REV, c.getType());
    assertEquals(QUEUE_TYPE_REV, c.getQueue());
    // if the lapse step is tomorrow, failing it should handle the counts
    // correctly
    c.setDue(0);
    c.flush();
    col.reset();
    assertEquals(new Counts(0, 0, 1), col.getSched().counts());
    conf = col.getSched()._cardConf(c);
    conf.getJSONObject("lapse").put("delays", new JSONArray(new double[] { 1440 }));
    col.getDecks().save(conf);
    c = getCard();
    col.getSched().answerCard(c, BUTTON_ONE);
    assertEquals(QUEUE_TYPE_DAY_LEARN_RELEARN, c.getQueue());
    assertEquals(new Counts(0, 0, 0), col.getSched().counts());
}
Also used : Note(com.ichi2.libanki.Note) JSONArray(com.ichi2.utils.JSONArray) Collection(com.ichi2.libanki.Collection) DeckConfig(com.ichi2.libanki.DeckConfig) Card(com.ichi2.libanki.Card) RobolectricTest(com.ichi2.anki.RobolectricTest) Test(org.junit.Test)

Example 22 with Counts

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

the class SchedV2Test method test_counts_idxV2.

@Test
public void test_counts_idxV2() throws Exception {
    Collection col = getColV2();
    Note note = col.newNote();
    note.setItem("Front", "one");
    note.setItem("Back", "two");
    col.addNote(note);
    col.reset();
    assertEquals(new Counts(1, 0, 0), col.getSched().counts());
    Card c = getCard();
    // counter's been decremented but idx indicates 1
    assertEquals(new Counts(0, 0, 0), col.getSched().counts());
    assertEquals(NEW, col.getSched().countIdx(c));
    // answer to move to learn queue
    col.getSched().answerCard(c, BUTTON_ONE);
    assertEquals(new Counts(0, 1, 0), col.getSched().counts());
    // fetching again will decrement the count
    c = getCard();
    assertEquals(new Counts(0, 0, 0), col.getSched().counts());
    assertEquals(LRN, col.getSched().countIdx(c));
    // answering should add it back again
    col.getSched().answerCard(c, BUTTON_ONE);
    assertEquals(new Counts(0, 1, 0), col.getSched().counts());
}
Also used : 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 23 with Counts

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

the class Reviewer method updateScreenCounts.

protected void updateScreenCounts() {
    if (mCurrentCard == null)
        return;
    super.updateActionBar();
    ActionBar actionBar = getSupportActionBar();
    Counts counts = mSched.counts(mCurrentCard);
    if (actionBar != null) {
        if (mPrefShowETA) {
            mEta = mSched.eta(counts, false);
            actionBar.setSubtitle(Utils.remainingTime(AnkiDroidApp.getInstance(), mEta * 60));
        }
    }
    mNewCount = new SpannableString(String.valueOf(counts.getNew()));
    mLrnCount = new SpannableString(String.valueOf(counts.getLrn()));
    mRevCount = new SpannableString(String.valueOf(counts.getRev()));
    if (mPrefHideDueCount) {
        mRevCount = new SpannableString("???");
    }
    switch(mSched.countIdx(mCurrentCard)) {
        case NEW:
            mNewCount.setSpan(new UnderlineSpan(), 0, mNewCount.length(), 0);
            break;
        case LRN:
            mLrnCount.setSpan(new UnderlineSpan(), 0, mLrnCount.length(), 0);
            break;
        case REV:
            mRevCount.setSpan(new UnderlineSpan(), 0, mRevCount.length(), 0);
            break;
        default:
            Timber.w("Unknown card type %s", mSched.countIdx(mCurrentCard));
            break;
    }
    mTextBarNew.setText(mNewCount);
    mTextBarLearn.setText(mLrnCount);
    mTextBarReview.setText(mRevCount);
}
Also used : SpannableString(android.text.SpannableString) Counts(com.ichi2.libanki.sched.Counts) ActionBar(androidx.appcompat.app.ActionBar) UnderlineSpan(android.text.style.UnderlineSpan)

Example 24 with Counts

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

the class Syncer method sanityCheck.

public JSONObject sanityCheck() {
    JSONObject result = new JSONObject();
    try {
        if (mCol.getDb().queryScalar("SELECT count() FROM cards WHERE nid NOT IN (SELECT id FROM notes)") != 0) {
            Timber.e("Sync - SanityCheck: there are cards without mother notes");
            result.put("client", "missing notes");
            return result;
        }
        if (mCol.getDb().queryScalar("SELECT count() FROM notes WHERE id NOT IN (SELECT DISTINCT nid FROM cards)") != 0) {
            Timber.e("Sync - SanityCheck: there are notes without cards");
            result.put("client", "missing cards");
            return result;
        }
        if (mCol.getDb().queryScalar("SELECT count() FROM cards WHERE usn = -1") != 0) {
            Timber.e("Sync - SanityCheck: there are unsynced cards");
            result.put("client", "cards had usn = -1");
            return result;
        }
        if (mCol.getDb().queryScalar("SELECT count() FROM notes WHERE usn = -1") != 0) {
            Timber.e("Sync - SanityCheck: there are unsynced notes");
            result.put("client", "notes had usn = -1");
            return result;
        }
        if (mCol.getDb().queryScalar("SELECT count() FROM revlog WHERE usn = -1") != 0) {
            Timber.e("Sync - SanityCheck: there are unsynced revlogs");
            result.put("client", "revlog had usn = -1");
            return result;
        }
        if (mCol.getDb().queryScalar("SELECT count() FROM graves WHERE usn = -1") != 0) {
            Timber.e("Sync - SanityCheck: there are unsynced graves");
            result.put("client", "graves had usn = -1");
            return result;
        }
        for (Deck g : mCol.getDecks().all()) {
            if (g.getInt("usn") == -1) {
                Timber.e("Sync - SanityCheck: unsynced deck: %s", g.getString("name"));
                result.put("client", "deck had usn = -1");
                return result;
            }
        }
        if (mCol.getTags().minusOneValue()) {
            Timber.e("Sync - SanityCheck: there are unsynced tags");
            result.put("client", "tag had usn = -1");
            return result;
        }
        boolean found = false;
        for (JSONObject m : mCol.getModels().all()) {
            if (mCol.getServer()) {
                // the web upgrade was mistakenly setting usn
                if (m.getInt("usn") < 0) {
                    m.put("usn", 0);
                    found = true;
                }
            } else {
                if (m.getInt("usn") == -1) {
                    Timber.e("Sync - SanityCheck: unsynced model: %s", m.getString("name"));
                    result.put("client", "model had usn = -1");
                    return result;
                }
            }
        }
        if (found) {
            mCol.getModels().save();
        }
        // check for missing parent decks
        mCol.getSched().deckDueList();
        // return summary of deck
        JSONArray check = new JSONArray();
        JSONArray counts = new JSONArray();
        // #5666 - not in libAnki
        // We modified mReportLimit inside the scheduler, and this causes issues syncing dynamic decks.
        AbstractSched syncScheduler = mCol.createScheduler(SYNC_SCHEDULER_REPORT_LIMIT);
        syncScheduler.resetCounts();
        Counts counts_ = syncScheduler.counts();
        counts.put(counts_.getNew());
        counts.put(counts_.getLrn());
        counts.put(counts_.getRev());
        check.put(counts);
        check.put(mCol.getDb().queryScalar("SELECT count() FROM cards"));
        check.put(mCol.getDb().queryScalar("SELECT count() FROM notes"));
        check.put(mCol.getDb().queryScalar("SELECT count() FROM revlog"));
        check.put(mCol.getDb().queryScalar("SELECT count() FROM graves"));
        check.put(mCol.getModels().all().size());
        check.put(mCol.getDecks().all().size());
        check.put(mCol.getDecks().allConf().size());
        result.put("client", check);
        return result;
    } catch (JSONException e) {
        Timber.e(e, "Syncer.sanityCheck()");
        throw new RuntimeException(e);
    }
}
Also used : Counts(com.ichi2.libanki.sched.Counts) JSONObject(com.ichi2.utils.JSONObject) AbstractSched(com.ichi2.libanki.sched.AbstractSched) JSONArray(com.ichi2.utils.JSONArray) Deck(com.ichi2.libanki.Deck) JSONException(com.ichi2.utils.JSONException)

Example 25 with Counts

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

the class SchedV2 method _walkingCount.

/**
 * @param limFn Method sending a deck to the maximal number of card it can have. Normally into account both limits and cards seen today
 * @param cntFn Method sending a deck to the number of card it has got to see today.
 * @param cancelListener Whether the task is not useful anymore
 * @return -1 if it's cancelled. Sum of the results of cntFn, limited by limFn,
 */
protected int _walkingCount(@NonNull LimitMethod limFn, @NonNull CountMethod cntFn, @Nullable CancelListener cancelListener) {
    int tot = 0;
    HashMap<Long, Integer> pcounts = HashUtil.HashMapInit(mCol.getDecks().count());
    // for each of the active decks
    for (long did : mCol.getDecks().active()) {
        if (isCancelled(cancelListener))
            return -1;
        // get the individual deck's limit
        int lim = limFn.operation(mCol.getDecks().get(did));
        if (lim == 0) {
            continue;
        }
        // check the parents
        List<Deck> parents = mCol.getDecks().parents(did);
        for (Deck p : parents) {
            // add if missing
            long id = p.getLong("id");
            if (!pcounts.containsKey(id)) {
                pcounts.put(id, limFn.operation(p));
            }
            // take minimum of child and parent
            lim = Math.min(pcounts.get(id), lim);
        }
        // see how many cards we actually have
        int cnt = cntFn.operation(did, lim);
        // if non-zero, decrement from parents counts
        for (Deck p : parents) {
            long id = p.getLong("id");
            pcounts.put(id, pcounts.get(id) - cnt);
        }
        // we may also be a parent
        pcounts.put(did, lim - cnt);
        // and add to running total
        tot += cnt;
    }
    return tot;
}
Also used : Deck(com.ichi2.libanki.Deck)

Aggregations

Collection (com.ichi2.libanki.Collection)47 Card (com.ichi2.libanki.Card)43 Test (org.junit.Test)39 RobolectricTest (com.ichi2.anki.RobolectricTest)38 Note (com.ichi2.libanki.Note)38 Deck (com.ichi2.libanki.Deck)12 DeckConfig (com.ichi2.libanki.DeckConfig)11 JSONArray (com.ichi2.utils.JSONArray)11 JSONObject (com.ichi2.utils.JSONObject)10 JSONException (com.ichi2.utils.JSONException)6 HashMap (java.util.HashMap)6 Resources (android.content.res.Resources)4 Nullable (androidx.annotation.Nullable)4 Model (com.ichi2.libanki.Model)4 AbstractDeckTreeNode (com.ichi2.libanki.sched.AbstractDeckTreeNode)4 IOException (java.io.IOException)4 Matchers.containsString (org.hamcrest.Matchers.containsString)4 JSONObject (org.json.JSONObject)4 Cursor (android.database.Cursor)3 ConfirmModSchemaException (com.ichi2.anki.exception.ConfirmModSchemaException)3