use of com.ichi2.libanki.utils.Time in project Anki-Android by ankidroid.
the class Decks method update.
/**
* {@inheritDoc}
*/
@Override
public void update(@NonNull Deck g) {
long id = g.getLong("id");
JSONObject oldDeck = get(id, false);
if (oldDeck != null) {
// In case where another update got the name
// `oldName`, it would be a mistake to remove it from nameMap
mNameMap.remove(oldDeck.getString("name"), oldDeck);
}
mNameMap.add(g);
mDecks.put(g.getLong("id"), g);
maybeAddToActive();
// mark registry changed, but don't bump mod time
save();
}
use of com.ichi2.libanki.utils.Time 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.libanki.utils.Time in project Anki-Android by ankidroid.
the class Storage method Collection.
public static Collection Collection(Context context, @NonNull String path, boolean server, boolean log, @NonNull Time time) {
assert (path.endsWith(".anki2") || path.endsWith(".anki21"));
File dbFile = new File(path);
boolean create = !dbFile.exists();
DroidBackend backend = DroidBackendFactory.getInstance(useBackend());
DB db = backend.openCollectionDatabase(sUseInMemory ? ":memory:" : path);
try {
// initialize
int ver;
if (create) {
ver = _createDB(db, time, backend);
} else {
ver = _upgradeSchema(db, time);
}
db.execute("PRAGMA temp_store = memory");
// add db to col and do any remaining upgrades
Collection col = backend.createCollection(context, db, path, server, log, time);
if (ver < Consts.SCHEMA_VERSION) {
_upgrade(col, ver);
} else if (ver > Consts.SCHEMA_VERSION) {
throw new RuntimeException("This file requires a newer version of Anki.");
} else if (create) {
addNoteTypes(col, backend);
col.onCreate();
col.save();
}
return col;
} catch (Exception e) {
Timber.e(e, "Error opening collection; closing database");
db.close();
throw e;
}
}
use of com.ichi2.libanki.utils.Time in project Anki-Android by ankidroid.
the class Storage method _setColVars.
private static void _setColVars(DB db, @NonNull Time time) {
JSONObject g = new JSONObject(Decks.DEFAULT_DECK);
g.put("id", 1);
g.put("name", "Default");
g.put("conf", 1);
g.put("mod", time.intTime());
JSONObject gc = new JSONObject(Decks.DEFAULT_CONF);
gc.put("id", 1);
JSONObject ag = new JSONObject();
ag.put("1", g);
JSONObject agc = new JSONObject();
agc.put("1", gc);
ContentValues values = new ContentValues();
values.put("conf", Collection.DEFAULT_CONF);
values.put("decks", Utils.jsonToString(ag));
values.put("dconf", Utils.jsonToString(agc));
db.update("col", values);
}
use of com.ichi2.libanki.utils.Time in project Anki-Android by ankidroid.
the class ModelFieldEditor method repositionFieldDialog.
/*
* Allows the user to select a number less than the number of fields in the current model to
* reposition the current field to
* Processing time is scales with number of items
*/
private void repositionFieldDialog() {
mFieldNameInput = new FixedEditText(this);
mFieldNameInput.setRawInputType(InputType.TYPE_CLASS_NUMBER);
new MaterialEditTextDialog.Builder(this, mFieldNameInput).title(String.format(getResources().getString(R.string.model_field_editor_reposition), 1, mFieldLabels.size())).positiveText(R.string.dialog_ok).onPositive((dialog, which) -> {
String newPosition = mFieldNameInput.getText().toString();
int pos;
try {
pos = Integer.parseInt(newPosition);
} catch (NumberFormatException n) {
Timber.w(n);
UIUtils.showThemedToast(this, getResources().getString(R.string.toast_out_of_range), true);
return;
}
if (pos < 1 || pos > mFieldLabels.size()) {
UIUtils.showThemedToast(this, getResources().getString(R.string.toast_out_of_range), true);
} else {
changeHandler listener = changeFieldHandler();
// Input is valid, now attempt to modify
try {
mCol.modSchema();
TaskManager.launchCollectionTask(new CollectionTask.RepositionField(mMod, mNoteFields.getJSONObject(mCurrentPos), pos - 1), listener);
} catch (ConfirmModSchemaException e) {
e.log();
// Handle mod schema confirmation
ConfirmationDialog c = new ConfirmationDialog();
c.setArgs(getResources().getString(R.string.full_sync_confirmation));
Runnable confirm = () -> {
try {
mCol.modSchemaNoCheck();
TaskManager.launchCollectionTask(new CollectionTask.RepositionField(mMod, mNoteFields.getJSONObject(mCurrentPos), pos - 1), listener);
dismissContextMenu();
} catch (JSONException e1) {
throw new RuntimeException(e1);
}
};
c.setConfirm(confirm);
c.setCancel(mConfirmDialogCancel);
ModelFieldEditor.this.showDialogFragment(c);
}
}
}).negativeText(R.string.dialog_cancel).show();
}
Aggregations