use of com.ichi2.libanki.utils.Time in project Anki-Android by ankidroid.
the class SchedTest method test_reviewsV1.
@Test
public void test_reviewsV1() throws Exception {
Collection col = getColV1();
// add a note
Note note = col.newNote();
note.setItem("Front", "one");
note.setItem("Back", "two");
col.addNote(note);
// set the card up as a review card, due 8 days ago
Card c = note.cards().get(0);
c.setType(CARD_TYPE_REV);
c.setQueue(QUEUE_TYPE_REV);
c.setDue(col.getSched().getToday() - 8);
c.setFactor(STARTING_FACTOR);
c.setReps(3);
c.setLapses(1);
c.setIvl(100);
c.startTimer();
c.flush();
// save it for later use as well
Card cardcopy = c.clone();
// failing it should put it in the learn queue with the default options
// //////////////////////////////////////////////////////////////////////////////////////////////////
// different delay to new
col.reset();
DeckConfig conf = col.getSched()._cardConf(c);
conf.getJSONObject("lapse").put("delays", new JSONArray(new double[] { 2, 20 }));
col.getDecks().save(conf);
col.getSched().answerCard(c, BUTTON_ONE);
assertEquals(QUEUE_TYPE_LRN, c.getQueue());
// it should be due tomorrow, with an interval of 1
assertEquals(col.getSched().getToday() + 1, c.getODue());
assertEquals(1, c.getIvl());
// but because it's in the learn queue, its current due time should be in
// the future
assertThat(c.getDue(), is(greaterThanOrEqualTo(col.getTime().intTime())));
assertThat(c.getDue() - col.getTime().intTime(), is(greaterThan(118L)));
// factor should have been decremented
assertEquals(2300, c.getFactor());
// check counters
assertEquals(2, c.getLapses());
assertEquals(4, c.getReps());
// check ests.
assertEquals(120, col.getSched().nextIvl(c, BUTTON_ONE));
assertEquals(20 * 60, col.getSched().nextIvl(c, BUTTON_TWO));
// try again with an ease of 2 instead
// //////////////////////////////////////////////////////////////////////////////////////////////////
c = cardcopy.clone();
c.flush();
col.getSched().answerCard(c, BUTTON_TWO);
assertEquals(QUEUE_TYPE_REV, c.getQueue());
// the new interval should be (100 + 8/4) * 1.2 = 122
assertTrue(checkRevIvl(col, c, 122));
assertEquals(col.getSched().getToday() + c.getIvl(), c.getDue());
// factor should have been decremented
assertEquals(2350, c.getFactor());
// check counters
assertEquals(1, c.getLapses());
assertEquals(4, c.getReps());
// ease 3
// //////////////////////////////////////////////////////////////////////////////////////////////////
c = cardcopy.clone();
c.flush();
col.getSched().answerCard(c, BUTTON_THREE);
// the new interval should be (100 + 8/2) * 2.5 = 260
assertTrue(checkRevIvl(col, c, 260));
assertEquals(col.getSched().getToday() + c.getIvl(), c.getDue());
// factor should have been left alone
assertEquals(STARTING_FACTOR, c.getFactor());
// ease 4
// //////////////////////////////////////////////////////////////////////////////////////////////////
c = cardcopy.clone();
c.flush();
col.getSched().answerCard(c, BUTTON_FOUR);
// the new interval should be (100 + 8) * 2.5 * 1.3 = 351
assertTrue(checkRevIvl(col, c, 351));
assertEquals(col.getSched().getToday() + c.getIvl(), c.getDue());
// factor should have been increased
assertEquals(2650, c.getFactor());
}
use of com.ichi2.libanki.utils.Time in project Anki-Android by ankidroid.
the class ModelFieldEditor method renameFieldDialog.
/*
* Creates a dialog to rename the currently selected field
* Processing time is constant
*/
private void renameFieldDialog() {
mFieldNameInput = new FixedEditText(this);
mFieldNameInput.setSingleLine(true);
mFieldNameInput.setText(mFieldLabels.get(mCurrentPos));
mFieldNameInput.setSelection(mFieldNameInput.getText().length());
new MaterialEditTextDialog.Builder(this, mFieldNameInput).title(R.string.model_field_editor_rename).positiveText(R.string.rename).onPositive((dialog, which) -> {
String fieldName = _uniqueName(mFieldNameInput);
if (fieldName == null) {
return;
}
// Field is valid, now rename
try {
renameField();
} catch (ConfirmModSchemaException e) {
e.log();
// Handler mod schema confirmation
ConfirmationDialog c = new ConfirmationDialog();
c.setArgs(getResources().getString(R.string.full_sync_confirmation));
Runnable confirm = () -> {
mCol.modSchemaNoCheck();
try {
renameField();
} catch (ConfirmModSchemaException e1) {
e1.log();
// This should never be thrown
}
dismissContextMenu();
};
c.setConfirm(confirm);
c.setCancel(mConfirmDialogCancel);
ModelFieldEditor.this.showDialogFragment(c);
}
}).negativeText(R.string.dialog_cancel).show();
}
use of com.ichi2.libanki.utils.Time in project Anki-Android by ankidroid.
the class AdvancedStatistics method calculateDueAsMetaInfo.
/**
* Determine forecast statistics based on a computation or simulation of future reviews.
* Returns all information required by stats.java to plot the 'forecast' chart based on these statistics.
* The chart will display:
* - The forecasted number of reviews per review type (relearn, mature, young, learn) as bars
* - The forecasted number of cards in each state (new, young, mature) as lines
* @param metaInfo Object which will be filled with all information required by stats.java to plot the 'forecast' chart and returned by this method.
* @param type Type of 'forecast' chart for which to determine forecast statistics. Accepted values:
* Stats.TYPE_MONTH: Determine forecast statistics for next 30 days with 1-day chunks
* Stats.TYPE_YEAR: Determine forecast statistics for next year with 7-day chunks
* Stats.TYPE_LIFE: Determine forecast statistics for next 2 years with 30-day chunks
* @param context Contains The collection which contains the decks to be simulated.
* Also used for access to the database and access to the creation time of the collection.
* The creation time of the collection is needed since due times of cards are relative to the creation time of the collection.
* So we could pass mCol here.
* @param dids Deck id's
* @return @see #metaInfo
*/
public StatsMetaInfo calculateDueAsMetaInfo(StatsMetaInfo metaInfo, Stats.AxisType type, Context context, String dids) {
if (!AnkiDroidApp.getSharedPrefs(context).getBoolean("advanced_statistics_enabled", false)) {
return metaInfo;
}
// To indicate that we calculated the statistics so that Stats.java knows that it shouldn't display the standard Forecast chart.
mSettings = new Settings(context);
metaInfo.setStatsCalculated(true);
Collection col = CollectionHelper.getInstance().getCol(context);
int maxCards = 0;
double lastElement = 0;
int zeroIndex = 0;
int[] valueLabels = { R.string.statistics_relearn, R.string.statistics_mature, R.string.statistics_young, R.string.statistics_learn };
int[] colors = { R.attr.stats_relearn, R.attr.stats_mature, R.attr.stats_young, R.attr.stats_learn };
int[] axisTitles = { type.ordinal(), R.string.stats_cards, R.string.stats_cumulative_cards };
PlottableSimulationResult simuationResult = calculateDueAsPlottableSimulationResult(type, col, dids);
ArrayList<int[]> dues = simuationResult.getNReviews();
double[][] seriesList = new double[REVIEW_TYPE_COUNT_PLUS_1][dues.size()];
for (int t = 0; t < dues.size(); t++) {
int[] data = dues.get(t);
int nReviews = data[REVIEW_TYPE_LEARN_PLUS_1] + data[REVIEW_TYPE_YOUNG_PLUS_1] + data[REVIEW_TYPE_MATURE_PLUS_1] + data[REVIEW_TYPE_RELEARN_PLUS_1];
if (nReviews > maxCards)
// Y-Axis: Max. value
maxCards = nReviews;
// In the bar-chart, the bars will be stacked on top of each other.
// For the i^{th} bar counting from the bottom we therefore have to
// provide the sum of the heights of the i^{th} bar and all bars below it.
// X-Axis: Day / Week / Month
seriesList[TIME][t] = data[TIME];
seriesList[REVIEW_TYPE_LEARN_PLUS_1][t] = data[REVIEW_TYPE_LEARN_PLUS_1] + data[REVIEW_TYPE_YOUNG_PLUS_1] + data[REVIEW_TYPE_MATURE_PLUS_1] + // Y-Axis: # Cards
data[REVIEW_TYPE_RELEARN_PLUS_1];
seriesList[REVIEW_TYPE_YOUNG_PLUS_1][t] = data[REVIEW_TYPE_LEARN_PLUS_1] + data[REVIEW_TYPE_YOUNG_PLUS_1] + // Y-Axis: # Mature cards
data[REVIEW_TYPE_MATURE_PLUS_1];
seriesList[REVIEW_TYPE_MATURE_PLUS_1][t] = data[REVIEW_TYPE_LEARN_PLUS_1] + // Y-Axis: # Young
data[REVIEW_TYPE_YOUNG_PLUS_1];
// Y-Axis: # Learn
seriesList[REVIEW_TYPE_RELEARN_PLUS_1][t] = data[REVIEW_TYPE_LEARN_PLUS_1];
if (data[TIME] > lastElement)
// X-Axis: Max. value (only for TYPE_LIFE)
lastElement = data[TIME];
if (data[TIME] == 0) {
// Because we retrieve dues in the past and we should not cumulate them
zeroIndex = t;
}
}
// # X values
int maxElements = dues.size() - 1;
switch(type) {
case TYPE_MONTH:
// X-Axis: Max. value
lastElement = 31;
break;
case TYPE_YEAR:
// X-Axis: Max. value
lastElement = 52;
break;
default:
}
// X-Axis: Min. value
double firstElement = 0;
// Day starting at zeroIndex, Cumulative # cards
double[][] cumulative = simuationResult.getNInState();
double count = // Y-Axis: Max. cumulative value
cumulative[CARD_TYPE_NEW_PLUS_1][cumulative[CARD_TYPE_NEW_PLUS_1].length - 1] + cumulative[CARD_TYPE_YOUNG_PLUS_1][cumulative[CARD_TYPE_YOUNG_PLUS_1].length - 1] + cumulative[CARD_TYPE_MATURE_PLUS_1][cumulative[CARD_TYPE_MATURE_PLUS_1].length - 1];
// some adjustments to not crash the chartbuilding with empty data
if (maxElements == 0) {
maxElements = 10;
}
if (count == 0) {
count = 10;
}
if (firstElement == lastElement) {
firstElement = 0;
lastElement = 6;
}
if (maxCards == 0)
maxCards = 10;
metaInfo.setmDynamicAxis(true);
metaInfo.setmHasColoredCumulative(true);
metaInfo.setmType(type);
metaInfo.setmTitle(R.string.stats_forecast);
metaInfo.setmBackwards(true);
metaInfo.setmValueLabels(valueLabels);
metaInfo.setmColors(colors);
metaInfo.setmAxisTitles(axisTitles);
metaInfo.setmMaxCards(maxCards);
metaInfo.setmMaxElements(maxElements);
metaInfo.setmFirstElement(firstElement);
metaInfo.setmLastElement(lastElement);
metaInfo.setmZeroIndex(zeroIndex);
metaInfo.setmCumulative(cumulative);
metaInfo.setmMcount(count);
metaInfo.setmSeriesList(seriesList);
metaInfo.setDataAvailable(!dues.isEmpty());
return metaInfo;
}
use of com.ichi2.libanki.utils.Time in project Anki-Android by ankidroid.
the class Utils method markAsUploaded.
/**
* Set usn to 0 in every object.
*
* This method is called during full sync, before uploading, so
* during an instant, the value will be zero while the object is
* not actually online. This is not a problem because if the sync
* fails, a full sync will occur again next time.
*
* @return whether there was a non-zero usn; in this case the list
* should be saved before the upload.
*/
public static boolean markAsUploaded(List<? extends JSONObject> ar) {
boolean changed = false;
for (JSONObject obj : ar) {
if (obj.optInt("usn", 1) != 0) {
obj.put("usn", 0);
changed = true;
}
}
return changed;
}
use of com.ichi2.libanki.utils.Time in project Anki-Android by ankidroid.
the class SchedV2 method quickDeckDueTree.
/**
* Similar to deck due tree, but ignore the number of cards.
*
* It may takes a lot of time to compute the number of card, it
* requires multiple database access by deck. Ignoring this number
* lead to the creation of a tree more quickly.
*/
@Override
@NonNull
public List<DeckTreeNode> quickDeckDueTree() {
// Similar to deckDueTree, ignoring the numbers
List<Deck> decks = mCol.getDecks().allSorted();
// Similar to deckDueList
ArrayList<DeckTreeNode> data = new ArrayList<>();
for (JSONObject deck : decks) {
DeckTreeNode g = new DeckTreeNode(mCol, deck.getString("name"), deck.getLong("id"));
data.add(g);
}
return _groupChildren(data, false);
}
Aggregations