Search in sources :

Example 61 with JSONObject

use of com.ichi2.utils.JSONObject in project AnkiChinaAndroid by ankichinateam.

the class SchedV2 method _delayForGrade.

protected int _delayForGrade(JSONObject conf, int left) {
    left = left % 1000;
    try {
        double delay;
        JSONArray delays = conf.getJSONArray("delays");
        int len = delays.length();
        try {
            delay = delays.getDouble(len - left);
        } catch (JSONException e) {
            if (conf.getJSONArray("delays").length() > 0) {
                delay = conf.getJSONArray("delays").getDouble(0);
            } else {
                // user deleted final step; use dummy value
                delay = 1.0;
            }
        }
        return (int) (delay * 60.0);
    } catch (JSONException e) {
        throw new RuntimeException(e);
    }
}
Also used : JSONArray(com.ichi2.utils.JSONArray) JSONException(com.ichi2.utils.JSONException)

Example 62 with JSONObject

use of com.ichi2.utils.JSONObject in project AnkiChinaAndroid by ankichinateam.

the class SchedV2 method _newConf.

// Overridden: different delays for filtered cards.
@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());
    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));
    dict.put("delays", oconf.getJSONObject("new").getJSONArray("delays"));
    // overrides
    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) DeckConfig(com.ichi2.libanki.DeckConfig) NonNull(androidx.annotation.NonNull)

Example 63 with JSONObject

use of com.ichi2.utils.JSONObject in project AnkiChinaAndroid by ankichinateam.

the class SchedV2 method _earlyReviewIvl.

/**
 * next interval for card when answered early+correctly
 */
private int _earlyReviewIvl(@NonNull Card card, @Consts.BUTTON_TYPE int ease) {
    if (card.getODid() == 0 || card.getType() != Consts.CARD_TYPE_REV || card.getFactor() == 0) {
        throw new RuntimeException("Unexpected card parameters");
    }
    if (ease <= 1) {
        throw new RuntimeException("Ease must be greater than 1");
    }
    long elapsed = card.getIvl() - (card.getODue() - mToday);
    @NonNull JSONObject conf = _revConf(card);
    double easyBonus = 1;
    // early 3/4 reviews shouldn't decrease previous interval
    double minNewIvl = 1;
    double factor;
    if (ease == Consts.BUTTON_TWO) {
        factor = conf.optDouble("hardFactor", 1.2);
        // hard cards shouldn't have their interval decreased by more than 50%
        // of the normal factor
        minNewIvl = factor / 2;
    } else if (ease == 3) {
        factor = card.getFactor() / 1000.0;
    } else {
        // ease == 4
        factor = card.getFactor() / 1000.0;
        double ease4 = conf.getDouble("ease4");
        // 1.3 -> 1.15
        easyBonus = ease4 - (ease4 - 1) / 2;
    }
    double ivl = Math.max(elapsed * factor, 1);
    // cap interval decreases
    ivl = Math.max(card.getIvl() * minNewIvl, ivl) * easyBonus;
    return _constrainedIvl(ivl, conf, 0, false);
}
Also used : JSONObject(com.ichi2.utils.JSONObject) NonNull(androidx.annotation.NonNull)

Example 64 with JSONObject

use of com.ichi2.utils.JSONObject in project AnkiChinaAndroid by ankichinateam.

the class MediaSyncer method sync.

public String sync(long restSpace) throws UnknownHttpResponseException, MediaSyncException, NoEnoughServerSpaceException {
    // of this class about this difference to the original.
    if (mCol.getMedia().needScan()) {
        mCon.publishProgress(R.string.sync_media_find);
        mCol.log("findChanges");
        try {
            mCol.getMedia().findChanges();
        } catch (SQLException ignored) {
            return "corruptMediaDB";
        }
    }
    // begin session and check if in sync
    int lastUsn = mCol.getMedia().lastUsn();
    JSONObject ret = mServer.begin();
    int srvUsn = ret.getInt("usn");
    if ((lastUsn == srvUsn) && !(mCol.getMedia().haveDirty())) {
        return "noChanges";
    }
    // loop through and process changes from server
    mCol.log("last local usn is " + lastUsn);
    mDownloadCount = 0;
    while (true) {
        // Allow cancellation (note: media sync has no finish command, so just throw)
        if (Connection.getIsCancelled()) {
            Timber.i("Sync was cancelled");
            throw new RuntimeException("UserAbortedSync");
        }
        JSONArray data = mServer.mediaChanges(lastUsn);
        mCol.log("mediaChanges resp count: ", data.length());
        if (data.length() == 0) {
            break;
        }
        List<String> need = new ArrayList<>();
        lastUsn = data.getJSONArray(data.length() - 1).getInt(1);
        for (int i = 0; i < data.length(); i++) {
            // Allow cancellation (note: media sync has no finish command, so just throw)
            if (Connection.getIsCancelled()) {
                Timber.i("Sync was cancelled");
                throw new RuntimeException("UserAbortedSync");
            }
            String fname = data.getJSONArray(i).getString(0);
            int rusn = data.getJSONArray(i).getInt(1);
            String rsum = null;
            if (!data.getJSONArray(i).isNull(2)) {
                // If `rsum` is a JSON `null` value, `.optString(2)` will
                // return `"null"` as a string
                rsum = data.getJSONArray(i).optString(2);
            }
            Pair<String, Integer> info = mCol.getMedia().syncInfo(fname);
            String lsum = info.first;
            int ldirty = info.second;
            mCol.log(String.format(Locale.US, "check: lsum=%s rsum=%s ldirty=%d rusn=%d fname=%s", TextUtils.isEmpty(lsum) ? "" : lsum.subSequence(0, 4), TextUtils.isEmpty(rsum) ? "" : rsum.subSequence(0, 4), ldirty, rusn, fname));
            if (!TextUtils.isEmpty(rsum)) {
                // added/changed remotely
                if (TextUtils.isEmpty(lsum) || !lsum.equals(rsum)) {
                    mCol.log("will fetch");
                    need.add(fname);
                } else {
                    mCol.log("have same already");
                }
                mCol.getMedia().markClean(Collections.singletonList(fname));
            } else if (!TextUtils.isEmpty(lsum)) {
                // deleted remotely
                if (ldirty == 0) {
                    mCol.log("delete local");
                    mCol.getMedia().syncDelete(fname);
                } else {
                    // conflict: local add overrides remote delete
                    mCol.log("conflict; will send");
                }
            } else {
                // deleted both sides
                mCol.log("both sides deleted");
                mCol.getMedia().markClean(Collections.singletonList(fname));
            }
        }
        _downloadFiles(need);
        mCol.log("update last usn to " + lastUsn);
        // commits
        mCol.getMedia().setLastUsn(lastUsn);
    }
    // at this point, we're all up to date with the server's changes,
    // and we need to send our own
    boolean updateConflict = false;
    int toSend = mCol.getMedia().dirtyCount();
    long needSize = mCol.getMedia().getMediaSizeNeededUpload();
    if (needSize >= 0 && restSpace < needSize && Consts.loginAnkiChina()) {
        Timber.d("No Enough Server Space Exception,rest is:" + restSpace + ",need size:" + needSize);
        throw new NoEnoughServerSpaceException(restSpace, needSize);
    }
    while (true) {
        Pair<File, List<String>> changesZip = mCol.getMedia().mediaChangesZip();
        File zip = changesZip.first;
        try {
            List<String> fnames = changesZip.second;
            if (fnames.size() == 0) {
                break;
            }
            mCon.publishProgress(String.format(AnkiDroidApp.getAppResources().getString(R.string.sync_media_changes_count), toSend));
            JSONArray changes = mServer.uploadChanges(zip);
            int processedCnt = changes.getInt(0);
            int serverLastUsn = changes.getInt(1);
            mCol.getMedia().markClean(fnames.subList(0, processedCnt));
            mCol.log(String.format(Locale.US, "processed %d, serverUsn %d, clientUsn %d", processedCnt, serverLastUsn, lastUsn));
            if (serverLastUsn - processedCnt == lastUsn) {
                mCol.log("lastUsn in sync, updating local");
                lastUsn = serverLastUsn;
                // commits
                mCol.getMedia().setLastUsn(serverLastUsn);
            } else {
                mCol.log("concurrent update, skipping usn update");
                // commit for markClean
                mCol.getMedia().getDb().commit();
                updateConflict = true;
            }
            toSend -= processedCnt;
        } finally {
            zip.delete();
        }
    }
    if (updateConflict) {
        mCol.log("restart sync due to concurrent update");
        return sync(restSpace);
    }
    int lcnt = mCol.getMedia().mediacount();
    String sRet = mServer.mediaSanity(lcnt);
    if ("OK".equals(sRet)) {
        return "OK";
    } else {
        mCol.getMedia().forceResync();
        return sRet;
    }
}
Also used : SQLException(android.database.SQLException) JSONArray(com.ichi2.utils.JSONArray) ArrayList(java.util.ArrayList) JSONObject(com.ichi2.utils.JSONObject) ArrayList(java.util.ArrayList) List(java.util.List) File(java.io.File) ZipFile(java.util.zip.ZipFile) NoEnoughServerSpaceException(com.ichi2.anki.exception.NoEnoughServerSpaceException)

Example 65 with JSONObject

use of com.ichi2.utils.JSONObject in project AnkiChinaAndroid by ankichinateam.

the class RemoteMediaServer method mediaSanity.

// args: local
public String mediaSanity(int lcnt) throws UnknownHttpResponseException, MediaSyncException {
    try {
        Response resp = super.req("mediaSanity", HttpSyncer.getInputStream(Utils.jsonToString(new JSONObject().put("local", lcnt))));
        JSONObject jresp = new JSONObject(resp.body().string());
        return _dataOnly(jresp, String.class);
    } catch (IOException | NullPointerException e) {
        throw new RuntimeException(e);
    }
}
Also used : Response(okhttp3.Response) JSONObject(com.ichi2.utils.JSONObject) IOException(java.io.IOException)

Aggregations

JSONObject (com.ichi2.utils.JSONObject)272 JSONArray (com.ichi2.utils.JSONArray)110 ArrayList (java.util.ArrayList)59 Test (org.junit.Test)55 Collection (com.ichi2.libanki.Collection)46 IOException (java.io.IOException)40 RobolectricTest (com.ichi2.anki.RobolectricTest)34 JSONException (com.ichi2.utils.JSONException)34 Note (com.ichi2.libanki.Note)33 Model (com.ichi2.libanki.Model)31 HashMap (java.util.HashMap)31 SuppressLint (android.annotation.SuppressLint)29 JSONObject (org.json.JSONObject)27 Response (okhttp3.Response)25 JSONException (org.json.JSONException)24 NonNull (androidx.annotation.NonNull)23 Card (com.ichi2.libanki.Card)21 File (java.io.File)21 Map (java.util.Map)20 Intent (android.content.Intent)19