Search in sources :

Example 6 with DeckConfig

use of com.ichi2.libanki.DeckConfig in project AnkiChinaAndroid by ankichinateam.

the class Sched method _deckRevLimitSingle.

/**
 * Maximal number of rev card still to see today in deck d. It's computed as:
 * the number of rev card to see by day according
 * minus the number of rev cards seen today in deck d or a descendant
 * plus the number of extra cards to see today in deck d, a parent or a descendant.
 *
 * Limits of its ancestors are not applied.  Current card is treated the same way as other cards.
 */
@Override
protected int _deckRevLimitSingle(@NonNull Deck d) {
    if (d.getInt("dyn") != 0) {
        return mReportLimit;
    }
    long did = d.getLong("id");
    DeckConfig c = mCol.getDecks().confForDid(did);
    int lim = Math.max(0, c.getJSONObject("rev").getInt("perDay") - d.getJSONArray("revToday").getInt(1));
    if (currentCardIsInQueueWithDeck(Consts.QUEUE_TYPE_REV, did)) {
        lim--;
    }
    // So currentCard does not have to be taken into consideration in this method
    return lim;
}
Also used : DeckConfig(com.ichi2.libanki.DeckConfig)

Example 7 with DeckConfig

use of com.ichi2.libanki.DeckConfig in project AnkiChinaAndroid by ankichinateam.

the class Sched method _lapseConf.

@Override
@NonNull
protected JSONObject _lapseConf(@NonNull Card card) {
    DeckConfig conf = _cardConf(card);
    // normal deck
    if (card.getODid() == 0) {
        return conf.getJSONObject("lapse");
    }
    // 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("lapse").getJSONArray("delays");
    }
    JSONObject dict = new JSONObject();
    // original deck
    dict.put("minInt", oconf.getJSONObject("lapse").getInt("minInt"));
    dict.put("leechFails", oconf.getJSONObject("lapse").getInt("leechFails"));
    dict.put("leechAction", oconf.getJSONObject("lapse").getInt("leechAction"));
    dict.put("mult", oconf.getJSONObject("lapse").getDouble("mult"));
    // overrides
    dict.put("delays", delays);
    dict.put("resched", conf.getBoolean("resched"));
    return dict;
}
Also used : JSONObject(com.ichi2.utils.JSONObject) JSONArray(com.ichi2.utils.JSONArray) DeckConfig(com.ichi2.libanki.DeckConfig) NonNull(androidx.annotation.NonNull)

Example 8 with DeckConfig

use of com.ichi2.libanki.DeckConfig 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 9 with DeckConfig

use of com.ichi2.libanki.DeckConfig 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)

Example 10 with DeckConfig

use of com.ichi2.libanki.DeckConfig in project AnkiChinaAndroid by ankichinateam.

the class Decks method load.

public void load(String decks, String dconf) {
    mDecks = new HashMap<>();
    mDconf = new HashMap<>();
    JSONObject decksarray = new JSONObject(decks);
    JSONArray ids = decksarray.names();
    for (int i = 0; i < ids.length(); i++) {
        String id = ids.getString(i);
        try {
            long longId = Long.parseLong(id);
            Deck o = new Deck(decksarray.getJSONObject(id));
            mDecks.put(longId, o);
        } catch (NumberFormatException e) {
            Timber.w("id is not valid");
        }
    }
    mNameMap = NameMap.constructor(mDecks.values());
    JSONObject confarray = new JSONObject(dconf);
    ids = confarray.names();
    for (int i = 0; ids != null && i < ids.length(); i++) {
        String id = ids.getString(i);
        try {
            mDconf.put(Long.parseLong(id), new DeckConfig(confarray.getJSONObject(id)));
        } catch (NumberFormatException e) {
            Timber.w("id is not valid");
        }
    }
    mChanged = false;
}
Also used : JSONObject(com.ichi2.utils.JSONObject) JSONArray(com.ichi2.utils.JSONArray)

Aggregations

DeckConfig (com.ichi2.libanki.DeckConfig)85 Collection (com.ichi2.libanki.Collection)57 Card (com.ichi2.libanki.Card)50 Test (org.junit.Test)49 RobolectricTest (com.ichi2.anki.RobolectricTest)48 Note (com.ichi2.libanki.Note)47 JSONArray (com.ichi2.utils.JSONArray)42 JSONObject (com.ichi2.utils.JSONObject)27 Deck (com.ichi2.libanki.Deck)14 NonNull (androidx.annotation.NonNull)12 Cursor (android.database.Cursor)5 JSONException (com.ichi2.utils.JSONException)5 ArrayList (java.util.ArrayList)5 Model (com.ichi2.libanki.Model)4 HashMap (java.util.HashMap)4 SuppressLint (android.annotation.SuppressLint)3 Map (java.util.Map)3 TreeMap (java.util.TreeMap)3 ContentValues (android.content.ContentValues)2 Intent (android.content.Intent)2