Search in sources :

Example 46 with CARD

use of com.ichi2.anki.CardBrowser.Column.CARD in project AnkiChinaAndroid by ankichinateam.

the class Sched method _newConf.

/**
 * Tools ******************************************************************** ***************************
 */
@Override
@NonNull
protected JSONObject _newConf(@NonNull Card card) {
    DeckConfig conf = _cardConf(card);
    // normal deck
    if (card.getODid() == 0) {
        return conf.getJSONObject("new");
    }
    // dynamic deck; override some attributes, use original deck for others
    DeckConfig oconf = mCol.getDecks().confForDid(card.getODid());
    JSONArray delays = conf.optJSONArray("delays");
    if (delays == null) {
        delays = oconf.getJSONObject("new").getJSONArray("delays");
    }
    JSONObject dict = new JSONObject();
    // original deck
    dict.put("ints", oconf.getJSONObject("new").getJSONArray("ints"));
    dict.put("initialFactor", oconf.getJSONObject("new").getInt("initialFactor"));
    dict.put("bury", oconf.getJSONObject("new").optBoolean("bury", true));
    // overrides
    dict.put("delays", delays);
    dict.put("separate", conf.getBoolean("separate"));
    dict.put("order", Consts.NEW_CARDS_DUE);
    dict.put("perDay", mReportLimit);
    return dict;
}
Also used : JSONObject(com.ichi2.utils.JSONObject) JSONArray(com.ichi2.utils.JSONArray) DeckConfig(com.ichi2.libanki.DeckConfig) NonNull(androidx.annotation.NonNull)

Example 47 with CARD

use of com.ichi2.anki.CardBrowser.Column.CARD in project AnkiChinaAndroid by ankichinateam.

the class SchedV2 method currentCardIsInQueueWithDeck.

protected boolean currentCardIsInQueueWithDeck(@Consts.CARD_QUEUE int queue, long did) {
    // mCurrentCard may be set to null when the reviewer gets closed. So we copy it to be sure to avoid NullPointerException
    Card currentCard = mCurrentCard;
    List<Long> currentCardParentsDid = mCurrentCardParentsDid;
    return currentCard != null && currentCard.getQueue() == queue && currentCardParentsDid != null && currentCardParentsDid.contains(did);
}
Also used : Card(com.ichi2.libanki.Card)

Example 48 with CARD

use of com.ichi2.anki.CardBrowser.Column.CARD in project AnkiChinaAndroid by ankichinateam.

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
    // Similar to deckDueList
    ArrayList<DeckTreeNode> data = new ArrayList<>();
    for (JSONObject deck : mCol.getDecks().allSorted()) {
        DeckTreeNode g = new DeckTreeNode(mCol, deck.getString("name"), deck.getLong("id"));
        data.add(g);
    }
    return _groupChildren(data, false);
}
Also used : JSONObject(com.ichi2.utils.JSONObject) ArrayList(java.util.ArrayList) NonNull(androidx.annotation.NonNull)

Example 49 with CARD

use of com.ichi2.anki.CardBrowser.Column.CARD in project AnkiChinaAndroid by ankichinateam.

the class Anki2Importer method _importCards.

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
    mCards = new HashMap<>();
    Map<Long, Boolean> existing = new HashMap<>();
    Cursor cur = null;
    try {
        cur = mDst.getDb().getDatabase().query("select f.guid, c.ord, c.id from cards c, notes f " + "where c.nid = f.id", null);
        while (cur.moveToNext()) {
            String guid = cur.getString(0);
            int ord = cur.getInt(1);
            long cid = cur.getLong(2);
            existing.put(cid, true);
            if (mCards.containsKey(guid)) {
                mCards.get(guid).put(ord, cid);
            } else {
                Map<Integer, Long> map = new HashMap<>();
                map.put(ord, cid);
                mCards.put(guid, map);
            }
        }
    } finally {
        if (cur != null) {
            cur.close();
        }
    }
    // loop through src
    List<Object[]> cards = new ArrayList<>();
    int totalCardCount = 0;
    final int thresExecCards = 1000;
    List<Object[]> revlog = new ArrayList<>();
    int totalRevlogCount = 0;
    final int thresExecRevlog = 1000;
    int usn = mDst.usn();
    long aheadBy = mSrc.getSched().getToday() - mDst.getSched().getToday();
    try {
        mDst.getDb().getDatabase().beginTransaction();
        cur = mSrc.getDb().getDatabase().query("select f.guid, f.mid, c.* from cards c, notes f " + "where c.nid = f.id", null);
        // Counters for progress updates
        int total = cur.getCount();
        boolean largeCollection = total > 200;
        int onePercent = total / 100;
        int i = 0;
        while (cur.moveToNext()) {
            Object[] card = new Object[] { cur.getString(0), cur.getLong(1), cur.getLong(2), cur.getLong(3), cur.getLong(4), cur.getInt(5), cur.getLong(6), cur.getInt(7), cur.getInt(8), cur.getInt(9), cur.getLong(10), cur.getLong(11), cur.getLong(12), cur.getInt(13), cur.getInt(14), cur.getInt(15), cur.getLong(16), cur.getLong(17), cur.getInt(18), cur.getString(19) };
            String guid = (String) card[0];
            if (mChangedGuids.containsKey(guid)) {
                guid = mChangedGuids.get(guid);
            }
            if (mIgnoredGuids.containsKey(guid)) {
                continue;
            }
            // does the card's note exist in dst col?
            if (!mNotes.containsKey(guid)) {
                continue;
            }
            Object[] dnid = mNotes.get(guid);
            // does the card already exist in the dst col?
            int ord = (Integer) card[5];
            if (mCards.containsKey(guid) && mCards.get(guid).containsKey(ord)) {
                // fixme: in future, could update if newer mod time
                continue;
            }
            // doesn't exist. strip off note info, and save src id for later
            Object[] oc = card;
            card = new Object[oc.length - 2];
            System.arraycopy(oc, 2, card, 0, card.length);
            long scid = (Long) card[0];
            // ensure the card id is unique
            while (existing.containsKey(card[0])) {
                card[0] = (Long) card[0] + 999;
            }
            existing.put((Long) card[0], true);
            // update cid, nid, etc
            card[1] = mNotes.get(guid)[0];
            card[2] = _did((Long) card[2]);
            if (mTopID < 0) {
                mTopID = (long) card[2];
            }
            card[4] = mCol.getTime().intTime();
            card[5] = usn;
            // review cards have a due date relative to collection
            if ((Integer) card[7] == 2 || (Integer) card[7] == 3 || (Integer) card[6] == 2) {
                card[8] = (Long) card[8] - aheadBy;
            }
            // odue needs updating too
            if (((Long) card[14]).longValue() != 0) {
                card[14] = (Long) card[14] - aheadBy;
            }
            // if odid true, convert card from filtered to normal
            if ((Long) card[15] != 0) {
                // odid
                card[15] = 0;
                // odue
                card[8] = card[14];
                card[14] = 0;
                // queue
                if ((Integer) card[6] == 1) {
                    // type
                    card[7] = 0;
                } else {
                    card[7] = card[6];
                }
                // type
                if ((Integer) card[6] == 1) {
                    card[6] = 0;
                }
            }
            cards.add(card);
            // we need to import revlog, rewriting card ids and bumping usn
            try (Cursor cur2 = mSrc.getDb().getDatabase().query("select * from revlog where cid = " + scid, null)) {
                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] = card[0];
                    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 {
        if (cur != null) {
            cur.close();
        }
        if (mDst.getDb().getDatabase().inTransaction()) {
            try {
                mDst.getDb().getDatabase().endTransaction();
            } catch (Exception e) {
                Timber.w(e);
            }
        }
    }
}
Also used : HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) Cursor(android.database.Cursor) ConfirmModSchemaException(com.ichi2.anki.exception.ConfirmModSchemaException) ImportExportException(com.ichi2.anki.exception.ImportExportException) IOException(java.io.IOException) FileNotFoundException(java.io.FileNotFoundException) ConfirmModSchemaException(com.ichi2.anki.exception.ConfirmModSchemaException)

Example 50 with CARD

use of com.ichi2.anki.CardBrowser.Column.CARD in project AnkiChinaAndroid by ankichinateam.

the class NoteImporter method importNotes.

/**
 * Convert each card into a note, apply attributes and add to col.
 */
public void importNotes(List<ForeignNote> notes) {
    Assert.that(mappingOk());
    // note whether tags are mapped
    mTagsMapped = false;
    for (String f : mMapping) {
        if ("_tags".equals(f)) {
            mTagsMapped = true;
            break;
        }
    }
    // gather checks for duplicate comparison
    HashMap<Long, List<Long>> csums = new HashMap<>();
    try (Cursor c = mCol.getDb().query("select csum, id from notes where mid = ?", mModel.getLong("id"))) {
        while (c.moveToNext()) {
            long csum = c.getLong(0);
            long id = c.getLong(1);
            if (csums.containsKey(csum)) {
                csums.get(csum).add(id);
            } else {
                csums.put(csum, new ArrayList<>(Collections.singletonList(id)));
            }
        }
    }
    HashMap<String, Boolean> firsts = new HashMap<>();
    int fld0index = mMapping.indexOf(mModel.getJSONArray("flds").getJSONObject(0).getString("name"));
    mFMap = mCol.getModels().fieldMap(mModel);
    mNextId = mCol.getTime().timestampID(mCol.getDb(), "notes");
    // loop through the notes
    List<Object[]> updates = new ArrayList<>();
    List<String> updateLog = new ArrayList<>();
    // PORT: Translations moved closer to their sources
    List<Object[]> _new = new ArrayList<>();
    _ids = new ArrayList<>();
    _cards = new ArrayList<>();
    mEmptyNotes = false;
    int dupeCount = 0;
    List<String> dupes = new ArrayList<>();
    for (ForeignNote n : notes) {
        for (int c = 0; c < n.mFields.size(); c++) {
            if (!this.mAllowHTML) {
                n.mFields.set(c, HtmlUtils.escape(n.mFields.get(c)));
            }
            n.mFields.set(c, n.mFields.get(c).trim());
            if (!this.mAllowHTML) {
                n.mFields.set(c, n.mFields.get(c).replace("\n", "<br>"));
            }
        }
        String fld0 = n.mFields.get(fld0index);
        long csum = fieldChecksum(fld0);
        // first field must exist
        if (fld0 == null || fld0.length() == 0) {
            getLog().add(getString(R.string.note_importer_error_empty_first_field, TextUtils.join(" ", n.mFields)));
            continue;
        }
        // earlier in import?
        if (firsts.containsKey(fld0) && mImportMode != ADD_MODE) {
            // duplicates in source file; log and ignore
            getLog().add(getString(R.string.note_importer_error_appeared_twice, fld0));
            continue;
        }
        firsts.put(fld0, true);
        // already exists?
        boolean found = false;
        if (csums.containsKey(csum)) {
            // csum is not a guarantee; have to check
            for (Long id : csums.get(csum)) {
                String flds = mCol.getDb().queryString("select flds from notes where id = ?", id);
                String[] sflds = splitFields(flds);
                if (fld0.equals(sflds[0])) {
                    // duplicate
                    found = true;
                    if (mImportMode == UPDATE_MODE) {
                        Object[] data = updateData(n, id, sflds);
                        if (data != null && data.length > 0) {
                            updates.add(data);
                            updateLog.add(getString(R.string.note_importer_error_first_field_matched, fld0));
                            dupeCount += 1;
                            found = true;
                        }
                    } else if (mImportMode == IGNORE_MODE) {
                        dupeCount += 1;
                    } else if (mImportMode == ADD_MODE) {
                        // allow duplicates in this case
                        if (!dupes.contains(fld0)) {
                            // only show message once, no matter how many
                            // duplicates are in the collection already
                            updateLog.add(getString(R.string.note_importer_error_added_duplicate_first_field, fld0));
                            dupes.add(fld0);
                        }
                        found = false;
                    }
                }
            }
        }
        // newly add
        if (!found) {
            Object[] data = newData(n);
            if (data != null && data.length > 0) {
                _new.add(data);
                // note that we've seen this note once already
                firsts.put(fld0, true);
            }
        }
    }
    addNew(_new);
    addUpdates(updates);
    // make sure to update sflds, etc
    mCol.updateFieldCache(collection2Array(_ids));
    // generate cards
    if (!mCol.genCards(_ids).isEmpty()) {
        this.getLog().add(0, getString(R.string.note_importer_empty_cards_found));
    }
    // apply scheduling updates
    updateCards();
    // we randomize or order here, to ensure that siblings
    // have the same due#
    long did = mCol.getDecks().selected();
    DeckConfig conf = mCol.getDecks().confForDid(did);
    // in order due?
    if (conf.getJSONObject("new").getInt("order") == NEW_CARDS_RANDOM) {
        mCol.getSched().randomizeCards(did);
    }
    String part1 = getQuantityString(R.plurals.note_importer_notes_added, _new.size());
    String part2 = getQuantityString(R.plurals.note_importer_notes_updated, mUpdateCount);
    int unchanged;
    if (mImportMode == UPDATE_MODE) {
        unchanged = dupeCount - mUpdateCount;
    } else if (mImportMode == IGNORE_MODE) {
        unchanged = dupeCount;
    } else {
        unchanged = 0;
    }
    String part3 = getQuantityString(R.plurals.note_importer_notes_unchanged, unchanged);
    mLog.add(String.format("%s, %s, %s.", part1, part2, part3));
    mLog.addAll(updateLog);
    if (mEmptyNotes) {
        mLog.add(getString(R.string.note_importer_error_empty_notes));
    }
    mTotal = _ids.size();
}
Also used : HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) Cursor(android.database.Cursor) ArrayList(java.util.ArrayList) List(java.util.List) JSONObject(com.ichi2.utils.JSONObject) DeckConfig(com.ichi2.libanki.DeckConfig)

Aggregations

Card (com.ichi2.libanki.Card)222 Test (org.junit.Test)212 Collection (com.ichi2.libanki.Collection)179 Note (com.ichi2.libanki.Note)173 RobolectricTest (com.ichi2.anki.RobolectricTest)168 JSONObject (com.ichi2.utils.JSONObject)114 JSONArray (com.ichi2.utils.JSONArray)80 DeckConfig (com.ichi2.libanki.DeckConfig)72 ArrayList (java.util.ArrayList)48 NonNull (androidx.annotation.NonNull)33 Deck (com.ichi2.libanki.Deck)32 Intent (android.content.Intent)29 JSONException (com.ichi2.utils.JSONException)27 Model (com.ichi2.libanki.Model)26 Context (android.content.Context)23 SuppressLint (android.annotation.SuppressLint)22 Cursor (android.database.Cursor)22 HashMap (java.util.HashMap)21 Matchers.containsString (org.hamcrest.Matchers.containsString)20 List (java.util.List)17