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());
}
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());
}
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);
}
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);
}
}
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;
}
Aggregations