use of com.ichi2.libanki.sched.Counts.Queue in project Anki-Android by ankidroid.
the class AbstractSchedTest method testUndoResetsCardCountsToCorrectValue.
@Test
public void testUndoResetsCardCountsToCorrectValue() throws InterruptedException {
// #6587
addNoteUsingBasicModel("Hello", "World");
Collection col = getCol();
AbstractSched sched = col.getSched();
col.reset();
Card cardBeforeUndo = sched.getCard();
Counts countsBeforeUndo = sched.counts();
// Not shown in the UI, but there is a state where the card has been removed from the queue, but not answered
// where the counts are decremented.
assertThat(countsBeforeUndo, is(new Counts(0, 0, 0)));
sched.answerCard(cardBeforeUndo, Consts.BUTTON_THREE);
waitFortask(new UndoService.Undo().toDelegate(), 5000);
Counts countsAfterUndo = sched.counts();
assertThat("Counts after an undo should be the same as before an undo", countsAfterUndo, is(countsBeforeUndo));
}
use of com.ichi2.libanki.sched.Counts.Queue in project Anki-Android by ankidroid.
the class Sched method _answerLrnCard.
/**
* @param ease 1=no, 2=yes, 3=remove
*/
@Override
protected void _answerLrnCard(@NonNull Card card, @Consts.BUTTON_TYPE int ease) {
JSONObject conf = _lrnConf(card);
@Consts.REVLOG_TYPE int type;
if (card.isInDynamicDeck() && !card.getWasNew()) {
type = Consts.REVLOG_CRAM;
} else if (card.getType() == Consts.CARD_TYPE_REV) {
type = Consts.REVLOG_RELRN;
} else {
type = Consts.REVLOG_LRN;
}
boolean leaving = false;
// lrnCount was decremented once when card was fetched
int lastLeft = card.getLeft();
// immediate graduate?
if (ease == Consts.BUTTON_THREE) {
_rescheduleAsRev(card, conf, true);
leaving = true;
// graduation time?
} else if (ease == Consts.BUTTON_TWO && (card.getLeft() % 1000) - 1 <= 0) {
_rescheduleAsRev(card, conf, false);
leaving = true;
} else {
// one step towards graduation
if (ease == Consts.BUTTON_TWO) {
// decrement real left count and recalculate left today
int left = (card.getLeft() % 1000) - 1;
card.setLeft(_leftToday(conf.getJSONArray("delays"), left) * 1000 + left);
// failed
} else {
card.setLeft(_startingLeft(card));
boolean resched = _resched(card);
if (conf.has("mult") && resched) {
// review that's lapsed
card.setIvl(Math.max(Math.max(1, (int) (card.getIvl() * conf.getDouble("mult"))), conf.getInt("minInt")));
} else {
// new card; no ivl adjustment
// pass
}
if (resched && card.isInDynamicDeck()) {
card.setODue(mToday + 1);
}
}
int delay = _delayForGrade(conf, card.getLeft());
if (card.getDue() < getTime().intTime()) {
// not collapsed; add some randomness
delay *= Utils.randomFloatInRange(1f, 1.25f);
}
card.setDue(getTime().intTime() + delay);
// due today?
if (card.getDue() < mDayCutoff) {
mLrnCount += card.getLeft() / 1000;
// if the queue is not empty and there's nothing else to do, make
// sure we don't put it at the head of the queue and end up showing
// it twice in a row
card.setQueue(Consts.QUEUE_TYPE_LRN);
if (!mLrnQueue.isEmpty() && revCount() == 0 && newCount() == 0) {
long smallestDue = mLrnQueue.getFirstDue();
card.setDue(Math.max(card.getDue(), smallestDue + 1));
}
_sortIntoLrn(card.getDue(), card.getId());
} else {
// the card is due in one or more days, so we need to use the day learn queue
long ahead = ((card.getDue() - mDayCutoff) / SECONDS_PER_DAY) + 1;
card.setDue(mToday + ahead);
card.setQueue(Consts.QUEUE_TYPE_DAY_LEARN_RELEARN);
}
}
_logLrn(card, ease, conf, leaving, type, lastLeft);
}
use of com.ichi2.libanki.sched.Counts.Queue in project Anki-Android by ankidroid.
the class Sched method _rescheduleLapse.
@Override
protected int _rescheduleLapse(@NonNull Card card) {
JSONObject conf = _lapseConf(card);
card.setLastIvl(card.getIvl());
if (_resched(card)) {
card.setLapses(card.getLapses() + 1);
card.setIvl(_nextLapseIvl(card, conf));
card.setFactor(Math.max(1300, card.getFactor() - 200));
card.setDue(mToday + card.getIvl());
// if it's a filtered deck, update odue as well
if (card.isInDynamicDeck()) {
card.setODue(card.getDue());
}
}
// if suspended as a leech, nothing to do
int delay = 0;
if (_checkLeech(card, conf) && card.getQueue() == Consts.QUEUE_TYPE_SUSPENDED) {
return delay;
}
// if no relearning steps, nothing to do
if (conf.getJSONArray("delays").length() == 0) {
return delay;
}
// record rev due date for later
if (card.getODue() == 0) {
card.setODue(card.getDue());
}
delay = _delayForGrade(conf, 0);
card.setDue(delay + getTime().intTime());
card.setLeft(_startingLeft(card));
// queue 1
if (card.getDue() < mDayCutoff) {
mLrnCount += card.getLeft() / 1000;
card.setQueue(Consts.QUEUE_TYPE_LRN);
_sortIntoLrn(card.getDue(), card.getId());
} else {
// day learn queue
long ahead = ((card.getDue() - mDayCutoff) / SECONDS_PER_DAY) + 1;
card.setDue(mToday + ahead);
card.setQueue(Consts.QUEUE_TYPE_DAY_LEARN_RELEARN);
}
return delay;
}
use of com.ichi2.libanki.sched.Counts.Queue in project Anki-Android by ankidroid.
the class SchedV2 method _burySiblings.
/**
* Sibling spacing
* ********************
*/
protected void _burySiblings(@NonNull Card card) {
ArrayList<Long> toBury = new ArrayList<>();
JSONObject nconf = _newConf(card);
boolean buryNew = nconf.optBoolean("bury", true);
JSONObject rconf = _revConf(card);
boolean buryRev = rconf.optBoolean("bury", true);
// loop through and remove from queues
try (Cursor cur = mCol.getDb().query("select id, queue from cards where nid=? and id!=? " + "and (queue=" + Consts.QUEUE_TYPE_NEW + " or (queue=" + Consts.QUEUE_TYPE_REV + " and due<=?))", card.getNid(), card.getId(), mToday)) {
while (cur.moveToNext()) {
long cid = cur.getLong(0);
int queue = cur.getInt(1);
SimpleCardQueue queue_object;
if (queue == Consts.QUEUE_TYPE_REV) {
queue_object = mRevQueue;
if (buryRev) {
toBury.add(cid);
}
} else {
queue_object = mNewQueue;
if (buryNew) {
toBury.add(cid);
}
}
// even if burying disabled, we still discard to give
// same-day spacing
queue_object.remove(cid);
}
}
// then bury
if (!toBury.isEmpty()) {
buryCards(Utils.collection2Array(toBury), false);
}
}
use of com.ichi2.libanki.sched.Counts.Queue in project Anki-Android by ankidroid.
the class SchedV2 method setCurrentCard.
/**
* This imitate the action of the method answerCard, except that it does not change the state of any card.
*
* It means in particular that: + it removes the siblings of card from all queues + change the next card if required
* it also set variables, so that when querying the next card, the current card can be taken into account.
*/
public void setCurrentCard(@NonNull Card card) {
mCurrentCard = card;
long did = card.getDid();
List<Deck> parents = mCol.getDecks().parents(did);
List<Long> currentCardParentsDid = new ArrayList<>(parents.size() + 1);
for (JSONObject parent : parents) {
currentCardParentsDid.add(parent.getLong("id"));
}
currentCardParentsDid.add(did);
// We set the member only once it is filled, to ensure we avoid null pointer exception if `discardCurrentCard`
// were called during `setCurrentCard`.
mCurrentCardParentsDid = currentCardParentsDid;
_burySiblings(card);
// if current card is next card or in the queue
mRevQueue.remove(card.getId());
mNewQueue.remove(card.getId());
}
Aggregations