Search in sources :

Example 36 with Model

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

the class Models method getTemplateNames.

public HashMap<Long, HashMap<Integer, String>> getTemplateNames() {
    HashMap<Long, HashMap<Integer, String>> result = new HashMap<>();
    for (Model m : mModels.values()) {
        JSONArray templates;
        templates = m.getJSONArray("tmpls");
        HashMap<Integer, String> names = new HashMap<>();
        for (int i = 0; i < templates.length(); i++) {
            JSONObject t = templates.getJSONObject(i);
            names.put(t.getInt("ord"), t.getString("name"));
        }
        result.put(m.getLong("id"), names);
    }
    return result;
}
Also used : JSONObject(com.ichi2.utils.JSONObject) HashMap(java.util.HashMap) JSONArray(com.ichi2.utils.JSONArray)

Example 37 with Model

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

the class Collection method _renderQA.

public HashMap<String, String> _renderQA(long cid, Model model, long did, int ord, String tags, String[] flist, int flags, boolean browser, String qfmt, String afmt) {
    // data is [cid, nid, mid, did, ord, tags, flds, cardFlags]
    // unpack fields and create dict
    Map<String, String> fields = new HashMap<>();
    Map<String, Pair<Integer, JSONObject>> fmap = Models.fieldMap(model);
    for (String name : fmap.keySet()) {
        fields.put(name, flist[fmap.get(name).first]);
    }
    int cardNum = ord + 1;
    fields.put("Tags", tags.trim());
    fields.put("Type", model.getString("name"));
    fields.put("Deck", mDecks.name(did));
    String baseName = Decks.basename(fields.get("Deck"));
    fields.put("Subdeck", baseName);
    fields.put("CardFlag", _flagNameFromCardFlags(flags));
    JSONObject template;
    if (model.getInt("type") == Consts.MODEL_STD) {
        template = model.getJSONArray("tmpls").getJSONObject(ord);
    } else {
        template = model.getJSONArray("tmpls").getJSONObject(0);
    }
    fields.put("Card", template.getString("name"));
    fields.put(String.format(Locale.US, "c%d", cardNum), "1");
    // render q & a
    HashMap<String, String> d = new HashMap<>();
    d.put("id", Long.toString(cid));
    qfmt = TextUtils.isEmpty(qfmt) ? template.getString("qfmt") : qfmt;
    afmt = TextUtils.isEmpty(afmt) ? template.getString("afmt") : afmt;
    for (Pair<String, String> p : new Pair[] { new Pair<>("q", qfmt), new Pair<>("a", afmt) }) {
        String type = p.first;
        String format = p.second;
        if ("q".equals(type)) {
            format = fClozePatternQ.matcher(format).replaceAll(String.format(Locale.US, "{{$1cq-%d:", cardNum));
            format = fClozeTagStart.matcher(format).replaceAll(String.format(Locale.US, "<%%cq:%d:", cardNum));
        } else {
            format = fClozePatternA.matcher(format).replaceAll(String.format(Locale.US, "{{$1ca-%d:", cardNum));
            format = fClozeTagStart.matcher(format).replaceAll(String.format(Locale.US, "<%%ca:%d:", cardNum));
            // the following line differs from libanki // TODO: why?
            // fields.put("FrontSide", mMedia.stripAudio(d.get("q")));
            fields.put("FrontSide", d.get("q"));
        }
        String html = new Template(format, fields).render();
        html = ChessFilter.fenToChessboard(html, getContext());
        if (!browser) {
            // browser don't show image. So compiling LaTeX actually remove information.
            html = LaTeX.mungeQA(html, this, model);
        }
        d.put(type, html);
        // empty cloze?
        if ("q".equals(type) && model.getInt("type") == Consts.MODEL_CLOZE) {
            if (getModels()._availClozeOrds(model, flist, false).size() == 0) {
                String link = String.format("<a href=%s#cloze>%s</a>", Consts.HELP_SITE, "help");
                d.put("q", mContext.getString(R.string.empty_cloze_warning, link));
            }
        }
    }
    return d;
}
Also used : JSONObject(com.ichi2.utils.JSONObject) HashMap(java.util.HashMap) SuppressLint(android.annotation.SuppressLint) Pair(android.util.Pair) Template(com.ichi2.libanki.template.Template)

Example 38 with Model

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

the class Syncer method mergeModels.

private void mergeModels(JSONArray rchg) throws UnexpectedSchemaChange {
    for (int i = 0; i < rchg.length(); i++) {
        Model r = new Model(rchg.getJSONObject(i));
        Model l = mCol.getModels().get(r.getLong("id"));
        // if missing locally or server is newer, update
        if (l == null || r.getLong("mod") > l.getLong("mod")) {
            // syncing algorithm should handle this in a better way.
            if (l != null) {
                if (l.getJSONArray("flds").length() != r.getJSONArray("flds").length()) {
                    throw new UnexpectedSchemaChange();
                }
                if (l.getJSONArray("tmpls").length() != r.getJSONArray("tmpls").length()) {
                    throw new UnexpectedSchemaChange();
                }
            }
            mCol.getModels().update(r);
        }
    }
}
Also used : Model(com.ichi2.libanki.Model)

Example 39 with Model

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

the class AnkiChinaSyncer method saveLatestData.

/**
 * 同步结束后将数据写入synclog
 */
@SuppressLint("DefaultLocale")
private void saveLatestData() {
    mCol = CollectionHelper.getInstance().getColSafe(AnkiDroidApp.getInstance());
    CollectionHelper.getInstance().lockCollection();
    mCol.getDb().getDatabase().beginTransaction();
    try {
        mCol.getDb().execute("delete from synclog");
    } catch (Exception e) {
        // mCol=CollectionHelper.getInstance().getColSafe(AnkiDroidApp.getInstance());
        // mCol.getDb().execute("drop table synclog");
        // mCol.getDb().execute("create table if not exists synclog (" + "    id             integer not null,"
        // + "    type             integer not null," + "    mod             integer not null" + ")");
        e.printStackTrace();
    }
    List<Deck> newDecks = mCol.getDecks().all();
    StringBuilder values = new StringBuilder();
    for (Deck item : newDecks) {
        if (values.length() != 0) {
            values.append(",");
        }
        values.append("(").append(item.getLong("id")).append(",").append(SYNC_LOG_TYPE_DECKS).append(",").append(item.getLong("mod")).append(")");
    }
    // db.execute(String.format("insert into synclog values %s",sbDeck.toString()));
    List<Model> newModels = mCol.getModels().all();
    // StringBuilder sbModel=new StringBuilder();
    for (Model item : newModels) {
        if (values.length() != 0) {
            values.append(",");
        }
        values.append("(").append(item.getLong("id")).append(",").append(SYNC_LOG_TYPE_MODELS).append(",").append(item.getLong("mod")).append(")");
    }
    // db.execute(String.format("insert into synclog values %s",sbModel.toString()));
    List<DeckConfig> newDConf = mCol.getDecks().allConf();
    // StringBuilder sbDConf=new StringBuilder();
    for (DeckConfig item : newDConf) {
        if (values.length() != 0) {
            values.append(",");
        }
        values.append("(").append(item.getLong("id")).append(",").append(SYNC_LOG_TYPE_DCONF).append(",").append(item.getLong("mod")).append(")");
    }
    String sql = String.format("insert into synclog values %s", values.toString());
    Timber.i("sync to local synclog:%s", sql);
    mCol.getDb().execute(sql);
    // List<Card> newDConf = mCol.getDecks().allConf();
    // for(DeckConfig item:newDConf){
    // if(values.length()!=0)values.append(",");
    // values.append("(").append(item.getLong("id")).append(",").append(SYNC_LOG_TYPE_DCONF).append(",").append(item.getLong("mod")).append(")");
    // }
    mCol.getDb().execute(String.format("insert into synclog select cards.id,%d,cards.mod from cards", SYNC_LOG_TYPE_CARD));
    mCol.getDb().execute(String.format("insert into synclog select notes.id,%d,notes.mod from notes", SYNC_LOG_TYPE_NOTE));
    mCol.getDb().execute(String.format("insert into synclog select revlog.id,%d,revlog.id from revlog", SYNC_LOG_TYPE_REVLOG));
    mCol.getDb().getDatabase().setTransactionSuccessful();
    mCol.getDb().getDatabase().endTransaction();
    // mCol.fixIntegrity(new CollectionTask.ProgressCallback(null, AnkiDroidApp.getAppResources()));
    CollectionHelper.getInstance().unlockCollection();
// db.execute(String.format("insert into synclog select revlog.id,%d,revlog.mod from revlog", SYNC_LOG_TYPE_REVLOG));
}
Also used : Model(com.ichi2.libanki.Model) Deck(com.ichi2.libanki.Deck) FileNotFoundException(java.io.FileNotFoundException) SQLiteConstraintException(android.database.sqlite.SQLiteConstraintException) IOException(java.io.IOException) DeckConfig(com.ichi2.libanki.DeckConfig) SuppressLint(android.annotation.SuppressLint)

Example 40 with Model

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

the class AnkiChinaSyncer method getChangedColJson.

private <T extends JSONObject> JSONObject getChangedColJson(int type, List<T> newModels) {
    List<T> changedModel = new ArrayList<>();
    boolean deleted;
    Cursor cur = null;
    Map<Long, Long> oldModel = new HashMap<>();
    JSONObject modelsJson = new JSONObject();
    try {
        cur = CollectionHelper.getInstance().getColSafe(AnkiDroidApp.getInstance()).getDb().getDatabase().query("SELECT id,mod FROM synclog WHERE type = " + type, null);
        while (cur.moveToNext()) {
            oldModel.put(cur.getLong(0), cur.getLong(1));
        }
    } finally {
        if (cur != null && !cur.isClosed()) {
            cur.close();
        }
    }
    if (oldModel.isEmpty()) {
        changedModel.addAll(newModels);
    } else {
        StringBuilder deletedModelSb = new StringBuilder();
        for (Map.Entry<Long, Long> entry : oldModel.entrySet()) {
            // System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
            deleted = true;
            for (T model : newModels) {
                if (!changedModel.contains(model) && (oldModel.get(model.getLong("id")) == null || oldModel.get(model.getLong("id")) < model.getLong("mod"))) {
                    // 新增或修改过的deck
                    changedModel.add(model);
                } else if (model.getLong("id") == entry.getKey()) {
                    // 未被删除的deck
                    deleted = false;
                }
            }
            if (deleted) {
                if (deletedModelSb.length() != 0) {
                    deletedModelSb.append(",");
                }
                deletedModelSb.append(entry.getKey());
            }
        }
        if (deletedModelSb.length() > 0) {
            modelsJson.put("delete", new JSONArray(deletedModelSb.toString().split(",")));
        // modelsJson.put("delete", strArray2jsonArray(deletedModelSb.toString().split(",")));
        }
    }
    JSONArray changedModelJson = new JSONArray();
    for (T item : changedModel) {
        changedModelJson.put(item);
    }
    modelsJson.put("replace", changedModelJson);
    return modelsJson;
}
Also used : HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) JSONArray(com.ichi2.utils.JSONArray) Cursor(android.database.Cursor) JSONObject(com.ichi2.utils.JSONObject) Map(java.util.Map) HashMap(java.util.HashMap)

Aggregations

JSONObject (com.ichi2.utils.JSONObject)124 Model (com.ichi2.libanki.Model)95 Test (org.junit.Test)82 JSONArray (com.ichi2.utils.JSONArray)79 Collection (com.ichi2.libanki.Collection)53 ArrayList (java.util.ArrayList)48 Note (com.ichi2.libanki.Note)40 RobolectricTest (com.ichi2.anki.RobolectricTest)38 JSONException (com.ichi2.utils.JSONException)32 Intent (android.content.Intent)30 Card (com.ichi2.libanki.Card)27 ConfirmModSchemaException (com.ichi2.anki.exception.ConfirmModSchemaException)26 HashMap (java.util.HashMap)22 Bundle (android.os.Bundle)20 NonNull (androidx.annotation.NonNull)20 SuppressLint (android.annotation.SuppressLint)16 View (android.view.View)16 ConfirmationDialog (com.ichi2.anki.dialogs.ConfirmationDialog)15 IOException (java.io.IOException)15 Nullable (androidx.annotation.Nullable)14