use of com.ichi2.anim.ActivityTransitionAnimation.LEFT in project Anki-Android by ankidroid.
the class SchedV2 method counts.
/**
* Same as counts(), but also count `card`. In practice, we use it because `card` is in the reviewer and that is the
* number we actually want.
* Overridden: left / 1000 in V1
*/
@NonNull
public Counts counts(@NonNull Card card) {
Counts counts = counts();
Queue idx = countIdx(card);
counts.changeCount(idx, 1);
return counts;
}
use of com.ichi2.anim.ActivityTransitionAnimation.LEFT in project Anki-Android by ankidroid.
the class SchedV2 method _getCard.
/*
Getting the next card ****************************************************
*******************************************
*/
/**
* Return the next due card, or null.
* Overridden: V1 does not allow dayLearnFirst
*/
@Nullable
protected Card _getCard() {
// learning card due?
@Nullable Card c = _getLrnCard(false);
if (c != null) {
return c;
}
// new first, or time for one?
if (_timeForNewCard()) {
c = _getNewCard();
if (c != null) {
return c;
}
}
// Day learning first and card due?
boolean dayLearnFirst = mCol.get_config("dayLearnFirst", false);
if (dayLearnFirst) {
c = _getLrnDayCard();
if (c != null) {
return c;
}
}
// Card due for review?
c = _getRevCard();
if (c != null) {
return c;
}
// day learning card due?
if (!dayLearnFirst) {
c = _getLrnDayCard();
if (c != null) {
return c;
}
}
// New cards left?
c = _getNewCard();
if (c != null) {
return c;
}
// collapse or finish
return _getLrnCard(true);
}
use of com.ichi2.anim.ActivityTransitionAnimation.LEFT in project Anki-Android by ankidroid.
the class Anki2Importer method _importCards.
/**
* Cards
* ***********************************************************
*/
private void _importCards() {
if (mMustResetLearning) {
try {
mSrc.changeSchedulerVer(2);
} catch (ConfirmModSchemaException e) {
throw new RuntimeException("Changing the scheduler of an import should not cause schema modification", e);
}
}
// build map of guid -> (ord -> cid) and used id cache
/*
* Since we can't use a tuple as a key in Java, we resort to indexing twice with nested maps.
* Python: (guid, ord) -> cid
* Java: guid -> ord -> cid
*/
int nbCard = mDst.cardCount();
Map<String, Map<Integer, Long>> cardsByGuid = HashUtil.HashMapInit(nbCard);
Set<Long> existing = HashUtil.HashSetInit(nbCard);
try (Cursor cur = mDst.getDb().query("select f.guid, c.ord, c.id from cards c, notes f " + "where c.nid = f.id")) {
while (cur.moveToNext()) {
String guid = cur.getString(0);
int ord = cur.getInt(1);
long cid = cur.getLong(2);
existing.add(cid);
if (cardsByGuid.containsKey(guid)) {
cardsByGuid.get(guid).put(ord, cid);
} else {
// The size is at most the number of card type in the note type.
Map<Integer, Long> map = new HashMap<>();
map.put(ord, cid);
cardsByGuid.put(guid, map);
}
}
}
// loop through src
int nbCardsToImport = mSrc.cardCount();
List<Object[]> cards = new ArrayList<>(nbCardsToImport);
int totalCardCount = 0;
final int thresExecCards = 1000;
List<Object[]> revlog = new ArrayList<>(mSrc.getSched().logCount());
int totalRevlogCount = 0;
final int thresExecRevlog = 1000;
int usn = mDst.usn();
long aheadBy = mSrc.getSched().getToday() - mDst.getSched().getToday();
mDst.getDb().getDatabase().beginTransaction();
try (Cursor cur = mSrc.getDb().query("select f.guid, c.id, c.did, c.ord, c.type, c.queue, c.due, c.ivl, c.factor, c.reps, c.lapses, c.left, c.odue, c.odid, c.flags, c.data from cards c, notes f " + "where c.nid = f.id")) {
// Counters for progress updates
int total = cur.getCount();
boolean largeCollection = total > 200;
int onePercent = total / 100;
int i = 0;
while (cur.moveToNext()) {
String guid = cur.getString(0);
long cid = cur.getLong(1);
// To keep track of card id in source
long scid = cid;
long did = cur.getLong(2);
int ord = cur.getInt(3);
@Consts.CARD_TYPE int type = cur.getInt(4);
@Consts.CARD_QUEUE int queue = cur.getInt(5);
long due = cur.getLong(6);
long ivl = cur.getLong(7);
long factor = cur.getLong(8);
int reps = cur.getInt(9);
int lapses = cur.getInt(10);
int left = cur.getInt(11);
long odue = cur.getLong(12);
long odid = cur.getLong(13);
int flags = cur.getInt(14);
String data = cur.getString(15);
if (mIgnoredGuids.contains(guid)) {
continue;
}
// does the card's note exist in dst col?
if (!mNotes.containsKey(guid)) {
continue;
}
NoteTriple dnid = mNotes.get(guid);
// does the card already exist in the dst col?
if (cardsByGuid.containsKey(guid) && cardsByGuid.get(guid).containsKey(ord)) {
// fixme: in future, could update if newer mod time
continue;
}
// ensure the card id is unique
while (existing.contains(cid)) {
cid += 999;
}
existing.add(cid);
// update cid, nid, etc
long nid = mNotes.get(guid).mNid;
did = _did(did);
long mod = mCol.getTime().intTime();
// review cards have a due date relative to collection
if (queue == QUEUE_TYPE_REV || queue == QUEUE_TYPE_DAY_LEARN_RELEARN || type == CARD_TYPE_REV) {
due -= aheadBy;
}
// odue needs updating too
if (odue != 0) {
odue -= aheadBy;
}
// if odid true, convert card from filtered to normal
if (odid != 0) {
// odid
odid = 0;
// odue
due = odue;
odue = 0;
// queue
if (type == CARD_TYPE_LRN) {
// type
queue = QUEUE_TYPE_NEW;
} else {
queue = type;
}
// type
if (type == CARD_TYPE_LRN) {
type = CARD_TYPE_NEW;
}
}
cards.add(new Object[] { cid, nid, did, ord, mod, usn, type, queue, due, ivl, factor, reps, lapses, left, odue, odid, flags, data });
// we need to import revlog, rewriting card ids and bumping usn
try (Cursor cur2 = mSrc.getDb().query("select * from revlog where cid = " + scid)) {
while (cur2.moveToNext()) {
Object[] rev = new Object[] { cur2.getLong(0), cur2.getLong(1), cur2.getInt(2), cur2.getInt(3), cur2.getLong(4), cur2.getLong(5), cur2.getLong(6), cur2.getLong(7), cur2.getInt(8) };
rev[1] = cid;
rev[2] = mDst.usn();
revlog.add(rev);
}
}
i++;
// apply card changes partially
if (cards.size() >= thresExecCards) {
totalCardCount += cards.size();
insertCards(cards);
cards.clear();
Timber.d("add cards: %d", totalCardCount);
}
// apply revlog changes partially
if (revlog.size() >= thresExecRevlog) {
totalRevlogCount += revlog.size();
insertRevlog(revlog);
revlog.clear();
Timber.d("add revlog: %d", totalRevlogCount);
}
if (total != 0 && (!largeCollection || i % onePercent == 0)) {
publishProgress(100, i * 100 / total, 0);
}
}
publishProgress(100, 100, 0);
// count total values
totalCardCount += cards.size();
totalRevlogCount += revlog.size();
Timber.d("add cards total: %d", totalCardCount);
Timber.d("add revlog total: %d", totalRevlogCount);
// apply (for last chunk)
insertCards(cards);
cards.clear();
insertRevlog(revlog);
revlog.clear();
mLog.add(getRes().getString(R.string.import_complete_count, totalCardCount));
mDst.getDb().getDatabase().setTransactionSuccessful();
} finally {
DB.safeEndInTransaction(mDst.getDb());
}
}
use of com.ichi2.anim.ActivityTransitionAnimation.LEFT in project Anki-Android by ankidroid.
the class Storage method _upgrade.
private static void _upgrade(Collection col, int ver) {
try {
if (ver < 3) {
// new deck properties
for (Deck d : col.getDecks().all()) {
d.put("dyn", DECK_STD);
d.put("collapsed", false);
col.getDecks().save(d);
}
}
if (ver < 4) {
col.modSchemaNoCheck();
List<Model> models = col.getModels().all();
ArrayList<Model> clozes = new ArrayList<>(models.size());
for (Model m : models) {
if (!m.getJSONArray("tmpls").getJSONObject(0).getString("qfmt").contains("{{cloze:")) {
m.put("type", Consts.MODEL_STD);
} else {
clozes.add(m);
}
}
for (Model m : clozes) {
try {
_upgradeClozeModel(col, m);
} catch (ConfirmModSchemaException e) {
// Will never be reached as we already set modSchemaNoCheck()
throw new RuntimeException(e);
}
}
col.getDb().execute("UPDATE col SET ver = 4");
}
if (ver < 5) {
col.getDb().execute("UPDATE cards SET odue = 0 WHERE queue = 2");
col.getDb().execute("UPDATE col SET ver = 5");
}
if (ver < 6) {
col.modSchemaNoCheck();
for (Model m : col.getModels().all()) {
m.put("css", new JSONObject(Models.DEFAULT_MODEL).getString("css"));
JSONArray ar = m.getJSONArray("tmpls");
for (JSONObject t : ar.jsonObjectIterable()) {
if (!t.has("css")) {
continue;
}
m.put("css", m.getString("css") + "\n" + t.getString("css").replace(".card ", ".card" + t.getInt("ord") + 1));
t.remove("css");
}
col.getModels().save(m);
}
col.getDb().execute("UPDATE col SET ver = 6");
}
if (ver < 7) {
col.modSchemaNoCheck();
col.getDb().execute("UPDATE cards SET odue = 0 WHERE (type = " + Consts.CARD_TYPE_LRN + " OR queue = 2) AND NOT odid");
col.getDb().execute("UPDATE col SET ver = 7");
}
if (ver < 8) {
col.modSchemaNoCheck();
col.getDb().execute("UPDATE cards SET due = due / 1000 WHERE due > 4294967296");
col.getDb().execute("UPDATE col SET ver = 8");
}
if (ver < 9) {
col.getDb().execute("UPDATE col SET ver = 9");
}
if (ver < 10) {
col.getDb().execute("UPDATE cards SET left = left + left * 1000 WHERE queue = " + Consts.QUEUE_TYPE_LRN);
col.getDb().execute("UPDATE col SET ver = 10");
}
if (ver < 11) {
col.modSchemaNoCheck();
for (Deck d : col.getDecks().all()) {
if (d.isDyn()) {
int order = d.getInt("order");
// failed order was removed
if (order >= 5) {
order -= 1;
}
JSONArray terms = new JSONArray(Arrays.asList(d.getString("search"), d.getInt("limit"), order));
d.put("terms", new JSONArray());
d.getJSONArray("terms").put(0, terms);
d.remove("search");
d.remove("limit");
d.remove("order");
d.put("resched", true);
d.put("return", true);
} else {
if (!d.has("extendNew")) {
d.put("extendNew", 10);
d.put("extendRev", 50);
}
}
col.getDecks().save(d);
}
for (DeckConfig c : col.getDecks().allConf()) {
JSONObject r = c.getJSONObject("rev");
r.put("ivlFct", r.optDouble("ivlFct", 1));
if (r.has("ivlfct")) {
r.remove("ivlfct");
}
r.put("maxIvl", 36500);
col.getDecks().save(c);
}
for (Model m : col.getModels().all()) {
JSONArray tmpls = m.getJSONArray("tmpls");
for (JSONObject t : tmpls.jsonObjectIterable()) {
t.put("bqfmt", "");
t.put("bafmt", "");
}
col.getModels().save(m);
}
col.getDb().execute("update col set ver = 11");
}
} catch (JSONException e) {
throw new RuntimeException(e);
}
}
use of com.ichi2.anim.ActivityTransitionAnimation.LEFT in project Anki-Android by ankidroid.
the class DeckPicker method showStartupScreensAndDialogs.
private void showStartupScreensAndDialogs(SharedPreferences preferences, int skip) {
// For Android 8/8.1 we want to use software rendering by default or the Reviewer UI is broken #7369
if (CompatHelper.getSdkVersion() == Build.VERSION_CODES.O || CompatHelper.getSdkVersion() == Build.VERSION_CODES.O_MR1) {
if (!preferences.contains("softwareRender")) {
Timber.i("Android 8/8.1 detected with no render preference. Turning on software render.");
preferences.edit().putBoolean("softwareRender", true).apply();
} else {
Timber.i("Android 8/8.1 detected, software render preference already exists.");
}
}
if (!BackupManager.enoughDiscSpace(CollectionHelper.getCurrentAnkiDroidDirectory(this))) {
Timber.i("Not enough space to do backup");
showDialogFragment(DeckPickerNoSpaceLeftDialog.newInstance());
} else if (preferences.getBoolean("noSpaceLeft", false)) {
Timber.i("No space left");
showDialogFragment(DeckPickerBackupNoSpaceLeftDialog.newInstance());
preferences.edit().remove("noSpaceLeft").apply();
} else if (InitialActivity.performSetupFromFreshInstallOrClearedPreferences(preferences)) {
onFinishedStartup();
} else if (skip < 2 && !InitialActivity.isLatestVersion(preferences)) {
Timber.i("AnkiDroid is being updated and a collection already exists.");
// The user might appreciate us now, see if they will help us get better?
if (!preferences.contains(UsageAnalytics.ANALYTICS_OPTIN_KEY)) {
displayAnalyticsOptInDialog();
}
// For upgrades, we check if we are upgrading
// to a version that contains additions to the database integrity check routine that we would
// like to run on all collections. A missing version number is assumed to be a fresh
// installation of AnkiDroid and we don't run the check.
long current = VersionUtils.getPkgVersionCode();
Timber.i("Current AnkiDroid version: %s", current);
long previous;
if (preferences.contains(UPGRADE_VERSION_KEY)) {
// Upgrading currently installed app
previous = getPreviousVersion(preferences, current);
} else {
// Fresh install
previous = current;
}
preferences.edit().putLong(UPGRADE_VERSION_KEY, current).apply();
// It is rebuilt on the next sync or media check
if (previous < 20300200) {
Timber.i("Deleting media database");
File mediaDb = new File(CollectionHelper.getCurrentAnkiDroidDirectory(this), "collection.media.ad.db2");
if (mediaDb.exists()) {
mediaDb.delete();
}
}
// Recommend the user to do a full-sync if they're upgrading from before 2.3.1beta8
if (previous < 20301208) {
Timber.i("Recommend the user to do a full-sync");
mRecommendFullSync = true;
}
// Fix "font-family" definition in templates created by AnkiDroid before 2.6alhpa23
if (previous < 20600123) {
Timber.i("Fixing font-family definition in templates");
try {
ModelManager models = getCol().getModels();
for (Model m : models.all()) {
String css = m.getString("css");
if (css.contains("font-familiy")) {
m.put("css", css.replace("font-familiy", "font-family"));
models.save(m);
}
}
models.flush();
} catch (JSONException e) {
Timber.e(e, "Failed to upgrade css definitions.");
}
}
// Check if preference upgrade or database check required, otherwise go to new feature screen
int upgradeDbVersion = AnkiDroidApp.CHECK_DB_AT_VERSION;
// Specifying a checkpoint in the future is not supported, please don't do it!
if (current < upgradeDbVersion) {
Timber.e("Invalid value for CHECK_DB_AT_VERSION");
UIUtils.showSimpleSnackbar(this, "Invalid value for CHECK_DB_AT_VERSION", false);
onFinishedStartup();
return;
}
// Skip full DB check if the basic check is OK
// TODO: remove this variable if we really want to do the full db check on every user
boolean skipDbCheck = false;
// if (previous < upgradeDbVersion && getCol().basicCheck()) {
// skipDbCheck = true;
// }
boolean upgradedPreferences = InitialActivity.upgradePreferences(this, previous);
// noinspection ConstantConditions
if (!skipDbCheck && previous < upgradeDbVersion) {
Timber.i("showStartupScreensAndDialogs() running integrityCheck()");
// #5852 - since we may have a warning about disk space, we don't want to force a check database
// and show a warning before the user knows what is happening.
new MaterialDialog.Builder(this).title(R.string.integrity_check_startup_title).content(R.string.integrity_check_startup_content).positiveText(R.string.check_db).negativeText(R.string.close).onPositive((materialDialog, dialogAction) -> integrityCheck()).onNeutral((materialDialog, dialogAction) -> restartActivity()).onNegative((materialDialog, dialogAction) -> restartActivity()).canceledOnTouchOutside(false).cancelable(false).build().show();
return;
}
if (upgradedPreferences) {
Timber.i("Updated preferences with no integrity check - restarting activity");
// If integrityCheck() doesn't occur, but we did update preferences we should restart DeckPicker to
// proceed
restartActivity();
return;
}
// There the "lastVersion" is set, so that this code is not reached again
if (VersionUtils.isReleaseVersion()) {
Timber.i("Displaying new features");
Intent infoIntent = new Intent(this, Info.class);
infoIntent.putExtra(Info.TYPE_EXTRA, Info.TYPE_NEW_VERSION);
if (skip != 0) {
startActivityForResultWithAnimation(infoIntent, SHOW_INFO_NEW_VERSION, START);
} else {
startActivityForResultWithoutAnimation(infoIntent, SHOW_INFO_NEW_VERSION);
}
} else {
Timber.i("Dev Build - not showing 'new features'");
// Don't show new features dialog for development builds
InitialActivity.setUpgradedToLatestVersion(preferences);
String ver = getResources().getString(R.string.updated_version, VersionUtils.getPkgVersionName());
UIUtils.showSnackbar(this, ver, true, -1, null, findViewById(R.id.root_layout), null);
showStartupScreensAndDialogs(preferences, 2);
}
} else {
// This is the main call when there is nothing special required
Timber.i("No startup screens required");
onFinishedStartup();
}
}
Aggregations