Search in sources :

Example 11 with Upgrade

use of com.ichi2.upgrade.Upgrade in project AnkiChinaAndroid by ankichinateam.

the class SelfStudyActivity method onCollectionLoaded.

// Finish initializing the activity after the collection has been correctly loaded
@Override
protected void onCollectionLoaded(Collection col) {
    super.onCollectionLoaded(col);
    Timber.d("onCollectionLoaded()");
    registerExternalStorageListener();
    final SharedPreferences preferences = AnkiDroidApp.getSharedPrefs(getBaseContext());
    // Load reference to action bar title
    mActionBarTitle = findViewById(R.id.toolbar_title);
    mTabLayout = findViewById(R.id.tab_layout);
    mTop = findViewById(R.id.invisible_top);
    mTop.setVisibility(View.GONE);
    mRestrictOnTab = "";
    mTabType = getIntent().getIntExtra("type", 0);
    mComplete = findViewById(R.id.tv_complete);
    mComplete.setOnClickListener(v -> toggleMultiSelectMode(false));
    mBack = findViewById(R.id.iv_back);
    mStartStudyButton = findViewById(R.id.confirm);
    mStartStudyButton.setOnClickListener(v -> {
        boolean showDialog = false;
        try {
            if (!preferences.getString(Consts.KEY_SELF_STUDYING_LIST, "").isEmpty()) {
                String[] savedCardListStr = preferences.getString(Consts.KEY_SELF_STUDYING_LIST, "").replace("[", "").replace("]", "").split(", ");
                long[] savedCardList = new long[savedCardListStr.length];
                for (int i = 0; i < savedCardListStr.length; i++) {
                    savedCardList[i] = Long.parseLong(savedCardListStr[i]);
                }
                List<Long> newCardList = getCol().filterToValidCards(savedCardList);
                long[] filterToValidCards = new long[newCardList.size()];
                for (int i = 0; i < newCardList.size(); i++) {
                    filterToValidCards[i] = newCardList.get(i);
                }
                if (preferences.getInt(Consts.KEY_SELF_STUDYING_LIST_INDEX, 0) + 1 < savedCardListStr.length) {
                    // 没跑完
                    Intent previewer = new Intent(SelfStudyActivity.this, Previewer2.class);
                    CustomStyleDialog studyDialog = new CustomStyleDialog.Builder(this).setCustomLayout(R.layout.dialog_common_custom_next).setTitle("是否继续上一次的主动练习?").centerTitle().setMessage("你上次的主动练习还有待学任务,请选择是继续上一次还是开始新的主动练习").setPositiveButton("开始新的", (dialog, which) -> {
                        dialog.dismiss();
                        long[] cardList;
                        if (inMultiSelectMode() && checkedCardCount() > 1) {
                            // Multiple cards have been explicitly selected, so preview only those cards
                            previewer.putExtra("index", 0);
                            cardList = getSelectedCardIds();
                        } else {
                            // Preview all cards, starting from the one that is currently selected
                            // int startIndex = mCheckedCards.isEmpty() ? 0 : mCheckedCards.iterator().next().getPosition();
                            previewer.putExtra("index", 0);
                            cardList = getAllCardIds();
                        }
                        previewer.putExtra("cardList", cardList);
                        preferences.edit().putString(Consts.KEY_SELF_STUDYING_LIST, Arrays.toString(cardList)).putInt(Consts.KEY_SELF_STUDYING_LIST_INDEX, 0).apply();
                        startActivityForResultWithoutAnimation(previewer, PREVIEW_CARDS);
                    }).setNegativeButton("继续上次", (dialog, which) -> {
                        dialog.dismiss();
                        previewer.putExtra("cardList", filterToValidCards);
                        previewer.putExtra("index", preferences.getInt(Consts.KEY_SELF_STUDYING_LIST_INDEX, 0));
                        startActivityForResultWithoutAnimation(previewer, PREVIEW_CARDS);
                    }).create();
                    showDialog = true;
                    studyDialog.show();
                }
            }
        } catch (Exception ignored) {
        }
        if (!showDialog) {
            Intent previewer = new Intent(SelfStudyActivity.this, Previewer2.class);
            long[] cardList;
            if (inMultiSelectMode() && checkedCardCount() > 1) {
                // Multiple cards have been explicitly selected, so preview only those cards
                previewer.putExtra("index", 0);
                cardList = getSelectedCardIds();
            } else {
                // Preview all cards, starting from the one that is currently selected
                // int startIndex = mCheckedCards.isEmpty() ? 0 : mCheckedCards.iterator().next().getPosition();
                previewer.putExtra("index", 0);
                cardList = getAllCardIds();
            }
            previewer.putExtra("cardList", cardList);
            preferences.edit().putString(Consts.KEY_SELF_STUDYING_LIST, Arrays.toString(cardList)).putInt(Consts.KEY_SELF_STUDYING_LIST_INDEX, 0).apply();
            startActivityForResultWithoutAnimation(previewer, PREVIEW_CARDS);
        }
    });
    // Add drop-down menu to select deck to action bar.
    mDropDownDecks = getCol().getDecks().allSorted();
    mDropDownDeckAdapter = new DeckDropDownAdapter(this, mDropDownDecks, R.layout.dropdown_deck_selected_item_self, this);
    mToolbar = findViewById(R.id.toolbar);
    if (mToolbar != null) {
        setSupportActionBar(mToolbar);
    // enable ActionBar app icon to behave as action to toggle nav drawer
    // getSupportActionBar().setDisplayHomeAsUpEnabled(true);
    // getSupportActionBar().setHomeButtonEnabled(true);
    // Decide which action to take when the navigation button is tapped.
    // mToolbar.setNavigationIcon(R.mipmap.nav_bar_back_normal);
    // mToolbar.setNavigationOnClickListener(v -> onBackPressed());
    }
    ActionBar mActionBar = getSupportActionBar();
    if (mActionBar != null) {
        mActionBar.setDisplayShowTitleEnabled(false);
    }
    // mOrder = CARD_ORDER_CREATE_TIME;
    String colOrder = getCol().getConf().getString("sortType");
    for (int c = 0; c < fSortTypes.length; ++c) {
        if (fSortTypes[c].equals(colOrder)) {
            mOrder = c;
            break;
        }
    }
    if (mOrder == 1 && preferences.getBoolean("cardBrowserNoSorting", false)) {
        mOrder = 0;
    }
    // This upgrade should already have been done during
    // setConf. However older version of AnkiDroid didn't call
    // upgradeJSONIfNecessary during setConf, which means the
    // conf saved may still have this bug.
    mOrderAsc = Upgrade.upgradeJSONIfNecessary(getCol(), getCol().getConf(), "sortBackwards", false);
    // mOrderAsc = true;
    getCol().getConf().put("sortType", fSortTypes[mOrder]);
    getCol().getConf().put("sortBackwards", mOrderAsc);
    mCards = new ArrayList<>();
    mCardsListView = findViewById(R.id.card_browser_list);
    mMultiModeBottomLayout = findViewById(R.id.rl_multi_mode);
    findViewById(R.id.add_note_action).setOnClickListener(v -> {
        Intent intent = new Intent(SelfStudyActivity.this, NoteEditor.class);
        intent.putExtra(NoteEditor.EXTRA_CALLER, NoteEditor.CALLER_CARDBROWSER_ADD);
        startActivityForResultWithAnimation(intent, ADD_NOTE, ActivityTransitionAnimation.LEFT);
    });
    TextView selectCount = findViewById(R.id.select_count);
    TextView move = findViewById(R.id.move);
    TextView delete = findViewById(R.id.delete);
    TextView cancel = findViewById(R.id.cancel);
    CheckBox stick = findViewById(R.id.stick);
    move.setOnClickListener(v -> {
        if (mCardsAdapter.getSelectedItemIds().isEmpty()) {
            return;
        }
        AlertDialog.Builder builderSingle = new AlertDialog.Builder(SelfStudyActivity.this);
        builderSingle.setTitle(getString(R.string.move_all_to_deck));
        // WARNING: changeDeck depends on this index, so any changes should be reflected there.
        final ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(SelfStudyActivity.this, R.layout.dropdown_deck_item);
        for (Deck deck : getValidDecksForChangeDeck()) {
            try {
                arrayAdapter.add(deck.getString("name"));
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }
        builderSingle.setNegativeButton(getString(R.string.cancel), (dialog, which) -> dialog.dismiss());
        builderSingle.setAdapter(arrayAdapter, (dialog, which) -> changeDeck(which));
        builderSingle.show();
    });
    delete.setOnClickListener(v -> {
        if (mCardsAdapter.getSelectedItemIds().isEmpty()) {
            return;
        }
        CollectionTask.launchCollectionTask(DISMISS_MULTI, mDeleteNoteHandler, new TaskData(new Object[] { mCardsAdapter.getSelectedItemIdArray(), Collection.DismissType.DELETE_NOTE_MULTI }));
        toggleMultiSelectMode(false);
        mCardsAdapter.getSelectedItemIds().clear();
        mCardsAdapter.notifyDataSetChanged();
    });
    int[] attrs = new int[] { R.attr.primary_text_third_color999999 };
    TypedArray ta = obtainStyledAttributes(attrs);
    int textGrayColor = ta.getColor(0, ContextCompat.getColor(this, R.color.new_primary_text_third_color));
    ta.recycle();
    stick.setOnCheckedChangeListener((buttonView, isChecked) -> {
        mCardsAdapter.selectItem(isChecked);
        selectCount.setText((isChecked ? "全选" : "已选") + mCardsAdapter.selectItemCount());
        selectCount.setTextColor(isChecked ? ContextCompat.getColor(this, R.color.primary_color) : textGrayColor);
    });
    selectCount.setOnClickListener(v -> stick.performClick());
    cancel.setOnClickListener(v -> {
        toggleMultiSelectMode(false);
    });
    mCardsAdapter = new CardsListAdapter(getLayoutInflater(), this, new CardsListAdapter.CardListAdapterCallback() {

        @Override
        public List<CardCache> getCards() {
            return SelfStudyActivity.this.getCards();
        }

        @Override
        public void onChangeMultiMode(boolean isMultiMode) {
            mMultiModeBottomLayout.setVisibility(isMultiMode ? View.VISIBLE : View.GONE);
            mStartStudyButton.setVisibility(isMultiMode ? View.GONE : mCards.size() > 0 ? View.VISIBLE : View.GONE);
            mSearchView.setVisibility(isMultiMode ? View.INVISIBLE : View.VISIBLE);
            mBack.setVisibility(isMultiMode ? View.GONE : View.VISIBLE);
            mComplete.setVisibility(isMultiMode ? View.VISIBLE : View.GONE);
            selectCount.setText("已选0");
            supportInvalidateOptionsMenu();
        }

        @Override
        public void onItemSelect(int count) {
            selectCount.setText("已选" + count);
            updateMultiselectMenu();
        }
    });
    // link the adapter to the main mCardsListView
    mCardsListView.setAdapter(mCardsAdapter);
    mCardsListView.setLayoutManager(new LinearLayoutManager(this));
    mCardsAdapter.setTvOrderClickListener(v -> showOrderListDialog());
    mCardsAdapter.setIvOrderClickListener(v -> {
        // 修改升序/降序
        mOrderAsc = !mOrderAsc;
        getCol().getConf().put("sortBackwards", mOrderAsc);
        Collections.reverse(mCards);
        updateList();
        mCardsAdapter.updateOrderState(mOrderNames[mOrder], mOrderAsc);
    });
    mCardsAdapter.setDeckClickListener(view -> {
        if (mCardsAdapter.isMultiCheckableMode()) {
            return;
        }
        Intent previewer = new Intent(SelfStudyActivity.this, Previewer.class);
        long[] ids = inMultiSelectMode() && checkedCardCount() > 1 ? getSelectedCardIds() : getAllCardIds();
        long targetId = (long) view.getTag();
        for (int i = 0; i < ids.length; i++) {
            if (ids[i] == targetId) {
                previewer.putExtra("index", i);
                break;
            }
        }
        previewer.putExtra("cardList", ids);
        startActivityForResultWithoutAnimation(previewer, PREVIEW_CARDS);
    // openNoteEditorForCard((long) view.getTag());
    });
    mCardsAdapter.setDeckLongClickListener(view -> {
        if (mCardsAdapter.isMultiCheckableMode()) {
            return false;
        }
        mCardsAdapter.setMultiCheckable(true);
        return true;
    });
    mCardsAdapter.setMarkClickListener(v -> {
        CollectionTask.launchCollectionTask(DISMISS_MULTI, markCardHandler(), new TaskData(new Object[] { new long[] { (long) v.getTag() }, Collection.DismissType.MARK_NOTE_MULTI }));
        mCardsAdapter.notifyDataSetChanged();
    });
    mOrderNames = getResources().getStringArray(R.array.card_browser_order_labels);
    mCardsAdapter.updateOrderState(mOrderNames[mOrder], mOrderAsc);
    mCardsAdapter.setFlagClickListener(v -> {
        if (mListPop == null) {
            mListPop = new ListPopupWindow(this);
            for (int i = 0; i < mFlagRes.length; i++) {
                Map<String, Object> map = new HashMap<>();
                map.put("img", mFlagRes[i]);
                map.put("content", mFlagContent[i]);
                mFlagList.add(map);
            }
            mListPop.setAdapter(new SimpleAdapter(SelfStudyActivity.this, mFlagList, R.layout.item_flags_list, new String[] { "img", "content" }, new int[] { R.id.flag_icon, R.id.flag_text }));
            mListPop.setWidth(v.getRootView().getWidth() / 2);
            mListPop.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);
            // 设置是否是模式
            mListPop.setModal(true);
        }
        mListPop.setOnItemClickListener((parent, view, position, id) -> {
            CollectionTask.launchCollectionTask(DISMISS_MULTI, flagCardHandler(), new TaskData(new Object[] { new long[] { (long) v.getTag() }, Collection.DismissType.FLAG, position }));
            mCardsAdapter.notifyDataSetChanged();
            mListPop.dismiss();
        });
        mListPop.setAnchorView(v);
        mListPop.show();
    });
    getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
    // If a valid value for last deck exists then use it, otherwise use libanki selected deck
    if ((getLastDeckId() != null && getLastDeckId() == ALL_DECKS_ID)) {
        selectAllDecks();
    } else if (getLastDeckId() != null && getCol().getDecks().get(getLastDeckId(), false) != null) {
        selectDeckById(getLastDeckId());
    } else {
        selectDeckById(getCol().getDecks().selected());
    }
    initSearchView();
    initTabLayout();
    findViewById(R.id.shadeView).setOnClickListener(v -> {
        if (mPopupWindow != null && mPopupWindow.isShowing()) {
            mPopupWindow.dismiss();
        }
        if (mOrderListWindow != null && mOrderListWindow.isShowing()) {
            mOrderListWindow.dismiss();
        }
    });
}
Also used : Arrays(java.util.Arrays) Bundle(android.os.Bundle) TagsDialog(com.ichi2.anki.dialogs.TagsDialog) Deck(com.ichi2.libanki.Deck) NonNull(androidx.annotation.NonNull) ImageView(android.widget.ImageView) RangeSeekBar(com.jaygoo.widget.RangeSeekBar) ActionBar(androidx.appcompat.app.ActionBar) Decks(com.ichi2.libanki.Decks) Handler(android.os.Handler) Map(java.util.Map) JSONException(com.ichi2.utils.JSONException) OnRangeChangedListener(com.jaygoo.widget.OnRangeChangedListener) ContextCompat(androidx.core.content.ContextCompat) DUE(com.ichi2.anki.CardBrowser.Column.DUE) Upgrade(com.ichi2.upgrade.Upgrade) CREATED(com.ichi2.anki.CardBrowser.Column.CREATED) IntentFilter(android.content.IntentFilter) Set(java.util.Set) JSONObject(com.ichi2.utils.JSONObject) SearchView(androidx.appcompat.widget.SearchView) INTERVAL(com.ichi2.anki.CardBrowser.Column.INTERVAL) Nullable(androidx.annotation.Nullable) CHANGED(com.ichi2.anki.CardBrowser.Column.CHANGED) Consts(com.ichi2.libanki.Consts) CardCache(com.ichi2.anki.CardBrowser.CardCache) LinearLayoutManager(androidx.recyclerview.widget.LinearLayoutManager) DECK(com.ichi2.anki.CardBrowser.Column.DECK) CARD(com.ichi2.anki.CardBrowser.Column.CARD) WarpLinearLayout(com.ichi2.ui.WarpLinearLayout) UPDATE_NOTE(com.ichi2.async.CollectionTask.TASK_TYPE.UPDATE_NOTE) NOTE_TYPE(com.ichi2.anki.CardBrowser.Column.NOTE_TYPE) TAGS(com.ichi2.anki.CardBrowser.Column.TAGS) SystemClock(android.os.SystemClock) RescheduleDialog(com.ichi2.anki.dialogs.RescheduleDialog) SdCardReceiver(com.ichi2.anki.receiver.SdCardReceiver) DISMISS_MULTI(com.ichi2.async.CollectionTask.TASK_TYPE.DISMISS_MULTI) Column(com.ichi2.anki.CardBrowser.Column) ArrayList(java.util.ArrayList) LAPSES(com.ichi2.anki.CardBrowser.Column.LAPSES) RENDER_BROWSER_QA(com.ichi2.async.CollectionTask.TASK_TYPE.RENDER_BROWSER_QA) SFLD(com.ichi2.anki.CardBrowser.Column.SFLD) Toast(android.widget.Toast) Menu(android.view.Menu) SimpleMessageDialog(com.ichi2.anki.dialogs.SimpleMessageDialog) REVIEWS(com.ichi2.anki.CardBrowser.Column.REVIEWS) IntegerDialog(com.ichi2.anki.dialogs.IntegerDialog) EASE(com.ichi2.anki.CardBrowser.Column.EASE) CheckResult(androidx.annotation.CheckResult) TextUtils(android.text.TextUtils) Gravity(android.view.Gravity) ArrayAdapter(android.widget.ArrayAdapter) SharedPreferences(android.content.SharedPreferences) TypedValue(android.util.TypedValue) ActivityTransitionAnimation(com.ichi2.anim.ActivityTransitionAnimation) CardBrowserOrderDialog(com.ichi2.anki.dialogs.CardBrowserOrderDialog) CardBrowser.sCardBrowserCard(com.ichi2.anki.CardBrowser.sCardBrowserCard) LinearLayout(android.widget.LinearLayout) WindowManager(android.view.WindowManager) UNDO(com.ichi2.async.CollectionTask.TASK_TYPE.UNDO) ConfirmationDialog(com.ichi2.anki.dialogs.ConfirmationDialog) Permissions(com.ichi2.utils.Permissions) FunctionalInterfaces(com.ichi2.utils.FunctionalInterfaces) CheckBox(android.widget.CheckBox) Locale(java.util.Locale) View(android.view.View) Button(android.widget.Button) TaskData(com.ichi2.async.TaskData) AdapterView(android.widget.AdapterView) RecyclerView(androidx.recyclerview.widget.RecyclerView) CardBrowserMySearchesDialog(com.ichi2.anki.dialogs.CardBrowserMySearchesDialog) TabLayout(com.google.android.material.tabs.TabLayout) SEARCH_CARDS(com.ichi2.async.CollectionTask.TASK_TYPE.SEARCH_CARDS) ANSWER(com.ichi2.anki.CardBrowser.Column.ANSWER) BroadcastReceiver(android.content.BroadcastReceiver) ViewGroup(android.view.ViewGroup) Timber(timber.log.Timber) AlertDialog(android.app.AlertDialog) Objects(java.util.Objects) List(java.util.List) TextView(android.widget.TextView) OnItemSelectedListener(android.widget.AdapterView.OnItemSelectedListener) SimpleAdapter(android.widget.SimpleAdapter) OrderListAdapter(com.ichi2.anki.widgets.OrderListAdapter) RelativeLayout(android.widget.RelativeLayout) Toolbar(androidx.appcompat.widget.Toolbar) TaskListenerWithContext(com.ichi2.async.TaskListenerWithContext) MaterialDialog(com.afollestad.materialdialogs.MaterialDialog) Snackbar(com.google.android.material.snackbar.Snackbar) Context(android.content.Context) EDITED(com.ichi2.anki.CardBrowser.Column.EDITED) Intent(android.content.Intent) HashMap(java.util.HashMap) CHECK_CARD_SELECTION(com.ichi2.async.CollectionTask.TASK_TYPE.CHECK_CARD_SELECTION) Collection(com.ichi2.libanki.Collection) TypedArray(android.content.res.TypedArray) MenuItem(android.view.MenuItem) InputMethodManager(android.view.inputmethod.InputMethodManager) HashSet(java.util.HashSet) CardsListAdapter(com.ichi2.anki.widgets.CardsListAdapter) DeckDropDownAdapter(com.ichi2.anki.widgets.DeckDropDownAdapter) WidgetStatus(com.ichi2.widget.WidgetStatus) QUESTION(com.ichi2.anki.CardBrowser.Column.QUESTION) Utils(com.ichi2.libanki.Utils) ListPopupWindow(androidx.appcompat.widget.ListPopupWindow) Iterator(java.util.Iterator) Stats(com.ichi2.libanki.stats.Stats) PopupWindow(android.widget.PopupWindow) CollectionTask(com.ichi2.async.CollectionTask) Spinner(android.widget.Spinner) KeyBoardListenerLayout(com.ichi2.ui.KeyBoardListenerLayout) Card(com.ichi2.libanki.Card) Collections(java.util.Collections) VisibleForTesting(androidx.annotation.VisibleForTesting) CustomStyleDialog(com.ichi2.ui.CustomStyleDialog) AlertDialog(android.app.AlertDialog) HashMap(java.util.HashMap) LinearLayoutManager(androidx.recyclerview.widget.LinearLayoutManager) DeckDropDownAdapter(com.ichi2.anki.widgets.DeckDropDownAdapter) TaskData(com.ichi2.async.TaskData) ListPopupWindow(androidx.appcompat.widget.ListPopupWindow) TypedArray(android.content.res.TypedArray) TextView(android.widget.TextView) ActionBar(androidx.appcompat.app.ActionBar) SharedPreferences(android.content.SharedPreferences) Deck(com.ichi2.libanki.Deck) JSONException(com.ichi2.utils.JSONException) SimpleAdapter(android.widget.SimpleAdapter) Intent(android.content.Intent) JSONException(com.ichi2.utils.JSONException) CardsListAdapter(com.ichi2.anki.widgets.CardsListAdapter) CardCache(com.ichi2.anki.CardBrowser.CardCache) CustomStyleDialog(com.ichi2.ui.CustomStyleDialog) CheckBox(android.widget.CheckBox) JSONObject(com.ichi2.utils.JSONObject) ArrayAdapter(android.widget.ArrayAdapter)

Example 12 with Upgrade

use of com.ichi2.upgrade.Upgrade in project AnkiChinaAndroid by ankichinateam.

the class DeckPicker method showStartupScreensAndDialogs.

public void showStartupScreensAndDialogs(SharedPreferences preferences, int skip) {
    if (!BackupManager.enoughDiscSpace(CollectionHelper.getCurrentAnkiDroidDirectory(this))) {
        Timber.i("Not enough space to do backup");
        showDialogFragment(DeckPickerNoSpaceLeftDialog.newInstance());
    } else if (preferences.getBoolean("noSpaceLeft", false)) {
        Timber.i("No space left");
        showDialogFragment(DeckPickerBackupNoSpaceLeftDialog.newInstance());
        preferences.edit().remove("noSpaceLeft").apply();
    } else if ("".equals(preferences.getString("lastVersion", ""))) {
        Timber.i("Fresh install");
        preferences.edit().putString("lastVersion", VersionUtils.getPkgVersionName()).apply();
        onFinishedStartup();
    } else if (skip < 2 && !preferences.getString("lastVersion", "").equals(VersionUtils.getPkgVersionName())) {
        Timber.i("AnkiDroid is being updated and a collection already exists.");
        // The user might appreciate us now, see if they will help us get better?
        if (!preferences.contains(UsageAnalytics.ANALYTICS_OPTIN_KEY)) {
            showDialogFragment(DeckPickerAnalyticsOptInDialog.newInstance());
        }
        // For upgrades, we check if we are upgrading
        // to a version that contains additions to the database integrity check routine that we would
        // like to run on all collections. A missing version number is assumed to be a fresh
        // installation of AnkiDroid and we don't run the check.
        long current = VersionUtils.getPkgVersionCode();
        Timber.i("Current AnkiDroid version: %s", current);
        long previous;
        if (preferences.contains(UPGRADE_VERSION_KEY)) {
            // Upgrading currently installed app
            previous = getPreviousVersion(preferences, current);
        } else {
            // Fresh install
            previous = current;
        }
        preferences.edit().putLong(UPGRADE_VERSION_KEY, current).apply();
        // It is rebuilt on the next sync or media check
        if (previous < 20300200) {
            Timber.i("Deleting media database");
            File mediaDb = new File(CollectionHelper.getCurrentAnkiDroidDirectory(this), "collection.media.ad.db2");
            if (mediaDb.exists()) {
                mediaDb.delete();
            }
        }
        // Recommend the user to do a full-sync if they're upgrading from before 2.3.1beta8
        if (previous < 20301208) {
            Timber.i("Recommend the user to do a full-sync");
            mRecommendFullSync = true;
        }
        // Fix "font-family" definition in templates created by AnkiDroid before 2.6alhpa23
        if (previous < 20600123) {
            Timber.i("Fixing font-family definition in templates");
            try {
                Models models = getCol().getModels();
                for (Model m : models.all()) {
                    String css = m.getString("css");
                    if (css.contains("font-familiy")) {
                        m.put("css", css.replace("font-familiy", "font-family"));
                        models.save(m);
                    }
                }
                models.flush();
            } catch (JSONException e) {
                Timber.e(e, "Failed to upgrade css definitions.");
            }
        }
        // Check if preference upgrade or database check required, otherwise go to new feature screen
        int upgradePrefsVersion = AnkiDroidApp.CHECK_PREFERENCES_AT_VERSION;
        int upgradeDbVersion = AnkiDroidApp.CHECK_DB_AT_VERSION;
        // Specifying a checkpoint in the future is not supported, please don't do it!
        if (current < upgradePrefsVersion) {
            Timber.e("Checkpoint in future produced.");
            UIUtils.showSimpleSnackbar(this, "Invalid value for CHECK_PREFERENCES_AT_VERSION", false);
            onFinishedStartup();
            return;
        }
        if (current < upgradeDbVersion) {
            Timber.e("Invalid value for CHECK_DB_AT_VERSION");
            UIUtils.showSimpleSnackbar(this, "Invalid value for CHECK_DB_AT_VERSION", false);
            onFinishedStartup();
            return;
        }
        // Skip full DB check if the basic check is OK
        // TODO: remove this variable if we really want to do the full db check on every user
        boolean skipDbCheck = false;
        // noinspection ConstantConditions
        if ((!skipDbCheck && previous < upgradeDbVersion) || previous < upgradePrefsVersion) {
            if (previous < upgradePrefsVersion) {
                Timber.i("showStartupScreensAndDialogs() running upgradePreferences()");
                upgradePreferences(previous);
            }
            // noinspection ConstantConditions
            if (!skipDbCheck && previous < upgradeDbVersion) {
                Timber.i("showStartupScreensAndDialogs() running integrityCheck()");
                // #5852 - since we may have a warning about disk space, we don't want to force a check database
                // and show a warning before the user knows what is happening.
                new MaterialDialog.Builder(this).title(R.string.integrity_check_startup_title).content(R.string.integrity_check_startup_content).positiveText(R.string.integrity_check_positive).negativeText(R.string.close).onPositive((materialDialog, dialogAction) -> integrityCheck()).onNeutral((materialDialog, dialogAction) -> this.restartActivity()).onNegative((materialDialog, dialogAction) -> this.restartActivity()).canceledOnTouchOutside(false).cancelable(false).build().show();
            } else if (previous < upgradePrefsVersion) {
                Timber.i("Updated preferences with no integrity check - restarting activity");
                // If integrityCheck() doesn't occur, but we did update preferences we should restart DeckPicker to
                // proceed
                this.restartActivity();
            }
        } else {
            // If no changes are required we go to the new features activity
            // There the "lastVersion" is set, so that this code is not reached again
            // if (VersionUtils.isReleaseVersion()) {
            // Timber.i("Displaying new features");
            // Intent infoIntent = new Intent(this, Info.class);
            // infoIntent.putExtra(Info.TYPE_EXTRA, Info.TYPE_NEW_VERSION);
            // 
            // if (skip != 0) {
            // startActivityForResultWithAnimation(infoIntent, SHOW_INFO_NEW_VERSION,
            // ActivityTransitionAnimation.LEFT);
            // } else {
            // startActivityForResultWithoutAnimation(infoIntent, SHOW_INFO_NEW_VERSION);
            // }
            // } else {
            Timber.i("Dev Build - not showing 'new features'");
            // Don't show new features dialog for development builds
            preferences.edit().putString("lastVersion", VersionUtils.getPkgVersionName()).apply();
            String ver = getResources().getString(R.string.updated_version, VersionUtils.getPkgVersionName());
            UIUtils.showSnackbar(this, ver, true, -1, null, findViewById(R.id.root_layout), null);
            showStartupScreensAndDialogs(preferences, 2);
        // }
        }
    } else {
        // this is the main call when there is nothing special required
        Timber.i("No startup screens required");
        onFinishedStartup();
    }
}
Also used : Bundle(android.os.Bundle) NonNull(androidx.annotation.NonNull) Uri(android.net.Uri) ImageView(android.widget.ImageView) ColorDrawable(android.graphics.drawable.ColorDrawable) DialogHandler(com.ichi2.anki.dialogs.DialogHandler) NavigationBarItemView(com.google.android.material.navigation.NavigationBarItemView) Manifest(android.Manifest) Decks(com.ichi2.libanki.Decks) Handler(android.os.Handler) JSONException(com.ichi2.utils.JSONException) Fragment(androidx.fragment.app.Fragment) ForegroundColorSpan(android.text.style.ForegroundColorSpan) ContextCompat(androidx.core.content.ContextCompat) DeckPickerBackupNoSpaceLeftDialog(com.ichi2.anki.dialogs.DeckPickerBackupNoSpaceLeftDialog) IntentFilter(android.content.IntentFilter) StringRes(androidx.annotation.StringRes) Nullable(androidx.annotation.Nullable) Message(android.os.Message) HostNumFactory(com.ichi2.anki.web.HostNumFactory) Consts(com.ichi2.libanki.Consts) OKHttpUtil(com.ichi2.utils.OKHttpUtil) MobclickAgent(com.umeng.analytics.MobclickAgent) DeckPickerExportCompleteDialog(com.ichi2.anki.dialogs.DeckPickerExportCompleteDialog) Models(com.ichi2.libanki.Models) SimpleDateFormat(java.text.SimpleDateFormat) Dialog(android.app.Dialog) SdCardReceiver(com.ichi2.anki.receiver.SdCardReceiver) URL_PRIVATE(com.ichi2.libanki.Consts.URL_PRIVATE) ArrayList(java.util.ArrayList) CustomSyncServerUrlException(com.ichi2.libanki.sync.CustomSyncServerUrlException) SpannableStringBuilder(android.text.SpannableStringBuilder) DeckPickerNoSpaceLeftDialog(com.ichi2.anki.dialogs.DeckPickerNoSpaceLeftDialog) Calendar(java.util.Calendar) Toast(android.widget.Toast) Menu(android.view.Menu) Connection(com.ichi2.async.Connection) Response(okhttp3.Response) AnkiPackageImporter(com.ichi2.libanki.importer.AnkiPackageImporter) Call(okhttp3.Call) CHECK_MEDIA(com.ichi2.async.CollectionTask.TASK_TYPE.CHECK_MEDIA) FragmentManager(androidx.fragment.app.FragmentManager) Beta(com.tencent.bugly.beta.Beta) SpannableString(android.text.SpannableString) ALL_DECKS_ID(com.ichi2.anki.SelfStudyActivity.ALL_DECKS_ID) URL_USER_PROTOCOL(com.ichi2.libanki.Consts.URL_USER_PROTOCOL) TextUtils(android.text.TextUtils) IOException(java.io.IOException) File(java.io.File) Gravity(android.view.Gravity) SharedPreferences(android.content.SharedPreferences) TypedValue(android.util.TypedValue) ActivityTransitionAnimation(com.ichi2.anim.ActivityTransitionAnimation) EditText(android.widget.EditText) AsyncDialogFragment(com.ichi2.anki.dialogs.AsyncDialogFragment) PackageManager(android.content.pm.PackageManager) Date(java.util.Date) WindowManager(android.view.WindowManager) UnderlineSpan(android.text.style.UnderlineSpan) UsageAnalytics(com.ichi2.anki.analytics.UsageAnalytics) ClickableSpan(android.text.style.ClickableSpan) ExportDialog(com.ichi2.anki.dialogs.ExportDialog) DeviceID(com.ichi2.libanki.DeviceID) ConfirmationDialog(com.ichi2.anki.dialogs.ConfirmationDialog) Permissions(com.ichi2.utils.Permissions) AnkiChinaSyncer(com.ichi2.libanki.sync.AnkiChinaSyncer) JSONObject(org.json.JSONObject) NOT_LOGIN_ANKI_CHINA(com.ichi2.anki.MyAccount.NOT_LOGIN_ANKI_CHINA) View(android.view.View) TaskData(com.ichi2.async.TaskData) SyncStatus(com.ichi2.utils.SyncStatus) FIND_EMPTY_CARDS(com.ichi2.async.CollectionTask.TASK_TYPE.FIND_EMPTY_CARDS) ParseException(java.text.ParseException) BottomNavigationView(com.google.android.material.bottomnavigation.BottomNavigationView) BroadcastReceiver(android.content.BroadcastReceiver) DatabaseErrorDialog(com.ichi2.anki.dialogs.DatabaseErrorDialog) DisplayMetrics(android.util.DisplayMetrics) ViewGroup(android.view.ViewGroup) Timber(timber.log.Timber) List(java.util.List) TextView(android.widget.TextView) RelativeLayout(android.widget.RelativeLayout) TaskListenerWithContext(com.ichi2.async.TaskListenerWithContext) ViewPropertyAnimator(android.view.ViewPropertyAnimator) MaterialDialog(com.afollestad.materialdialogs.MaterialDialog) Window(android.view.Window) VersionUtils(com.ichi2.utils.VersionUtils) Context(android.content.Context) TaskListener(com.ichi2.async.TaskListener) Spanned(android.text.Spanned) KeyEvent(android.view.KeyEvent) GravityEnum(com.afollestad.materialdialogs.GravityEnum) DeckPickerAnalyticsOptInDialog(com.ichi2.anki.dialogs.DeckPickerAnalyticsOptInDialog) Intent(android.content.Intent) ViewPager2(androidx.viewpager2.widget.ViewPager2) Collection(com.ichi2.libanki.Collection) StyledProgressDialog(com.ichi2.themes.StyledProgressDialog) MenuItem(android.view.MenuItem) FragmentStateAdapter(androidx.viewpager2.adapter.FragmentStateAdapter) CHECK_DATABASE(com.ichi2.async.CollectionTask.TASK_TYPE.CHECK_DATABASE) Lifecycle(androidx.lifecycle.Lifecycle) REPAIR_COLLECTION(com.ichi2.async.CollectionTask.TASK_TYPE.REPAIR_COLLECTION) WidgetStatus(com.ichi2.widget.WidgetStatus) MotionEvent(android.view.MotionEvent) SyncErrorDialog(com.ichi2.anki.dialogs.SyncErrorDialog) Model(com.ichi2.libanki.Model) ConfirmModSchemaException(com.ichi2.anki.exception.ConfirmModSchemaException) Bugly(com.tencent.bugly.Bugly) LOAD_COLLECTION_COMPLETE(com.ichi2.async.CollectionTask.TASK_TYPE.LOAD_COLLECTION_COMPLETE) UMConfigure(com.umeng.commonsdk.UMConfigure) PlatformConfig(com.umeng.socialize.PlatformConfig) ActivityCompat(androidx.core.app.ActivityCompat) CollectionTask(com.ichi2.async.CollectionTask) BottomNavigationMenuView(com.google.android.material.bottomnavigation.BottomNavigationMenuView) Color(android.graphics.Color) MediaCheckDialog(com.ichi2.anki.dialogs.MediaCheckDialog) LOAD_DECK_COUNTS(com.ichi2.async.CollectionTask.TASK_TYPE.LOAD_DECK_COUNTS) VisibleForTesting(androidx.annotation.VisibleForTesting) CustomStyleDialog(com.ichi2.ui.CustomStyleDialog) Resources(android.content.res.Resources) SpannableStringBuilder(android.text.SpannableStringBuilder) Model(com.ichi2.libanki.Model) JSONException(com.ichi2.utils.JSONException) Models(com.ichi2.libanki.Models) SpannableString(android.text.SpannableString) File(java.io.File)

Example 13 with Upgrade

use of com.ichi2.upgrade.Upgrade in project AnkiChinaAndroid by ankichinateam.

the class DeckPicker method onFinishedStartup.

/**
 * Perform the following tasks:
 * Automatic backup
 * loadStudyOptionsFragment() if tablet
 * Automatic sync
 */
private void onFinishedStartup() {
    // create backup in background if needed
    if (getCol() == null) {
        return;
    }
    SharedPreferences preferences = AnkiDroidApp.getSharedPrefs(this);
    if (preferences.getBoolean(AUTO_TURN_TO_LOGIN, true) && !Consts.isLogin()) {
        Intent myAccount = new Intent(this, MyAccount.class);
        myAccount.putExtra("notLoggedIn", true);
        startActivityForResultWithAnimation(myAccount, LOG_IN_FOR_SYNC, ActivityTransitionAnimation.FADE);
        preferences.edit().putBoolean(AUTO_TURN_TO_LOGIN, false).apply();
    }
    BackupManager.performBackupInBackground(getCol().getPath(), getCol().getTime());
    // Force a full sync if flag was set in upgrade path, asking the user to confirm if necessary
    if (mRecommendFullSync) {
        mRecommendFullSync = false;
        try {
            getCol().modSchema();
        } catch (ConfirmModSchemaException e) {
            Timber.w("Forcing full sync");
            // If libanki determines it's necessary to confirm the full sync then show a confirmation dialog
            // We have to show the dialog via the DialogHandler since this method is called via an async task
            Resources res = getResources();
            Message handlerMessage = Message.obtain();
            handlerMessage.what = DialogHandler.MSG_SHOW_FORCE_FULL_SYNC_DIALOG;
            Bundle handlerMessageData = new Bundle();
            handlerMessageData.putString("message", res.getString(R.string.full_sync_confirmation_upgrade) + "\n\n" + res.getString(R.string.full_sync_confirmation));
            handlerMessage.setData(handlerMessageData);
            getDialogHandler().sendMessage(handlerMessage);
        }
    }
    // Open StudyOptionsFragment if in fragmented mode
    automaticSync();
}
Also used : Message(android.os.Message) SharedPreferences(android.content.SharedPreferences) Bundle(android.os.Bundle) ConfirmModSchemaException(com.ichi2.anki.exception.ConfirmModSchemaException) Intent(android.content.Intent) Resources(android.content.res.Resources)

Example 14 with Upgrade

use of com.ichi2.upgrade.Upgrade in project AnkiChinaAndroid by ankichinateam.

the class CardBrowser method onCollectionLoaded.

// Finish initializing the activity after the collection has been correctly loaded
@Override
protected void onCollectionLoaded(Collection col) {
    super.onCollectionLoaded(col);
    Timber.d("onCollectionLoaded()");
    registerExternalStorageListener();
    SharedPreferences preferences = AnkiDroidApp.getSharedPrefs(getBaseContext());
    // Load reference to action bar title
    mActionBarTitle = (TextView) findViewById(R.id.toolbar_title);
    // Add drop-down menu to select deck to action bar.
    mDropDownDecks = getCol().getDecks().allSorted();
    mDropDownAdapter = new DeckDropDownAdapter(this, mDropDownDecks, R.layout.dropdown_deck_selected_item, this);
    Toolbar toolbar = findViewById(R.id.toolbar);
    if (toolbar != null) {
        setSupportActionBar(toolbar);
        // enable ActionBar app icon to behave as action to toggle nav drawer
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        getSupportActionBar().setHomeButtonEnabled(true);
        // Decide which action to take when the navigation button is tapped.
        toolbar.setNavigationOnClickListener(v -> finishActivityWithFade(this, ActivityTransitionAnimation.RIGHT));
    }
    ActionBar mActionBar = getSupportActionBar();
    if (mActionBar != null) {
        mActionBar.setDisplayShowTitleEnabled(false);
    }
    mActionBarSpinner = (Spinner) findViewById(R.id.toolbar_spinner);
    mActionBarSpinner.setAdapter(mDropDownAdapter);
    mActionBarSpinner.setOnItemSelectedListener(new OnItemSelectedListener() {

        @Override
        public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
            deckDropDownItemChanged(position);
        }

        @Override
        public void onNothingSelected(AdapterView<?> parent) {
        // do nothing
        }
    });
    mActionBarSpinner.setVisibility(View.VISIBLE);
    mOrder = CARD_ORDER_NONE;
    String colOrder = getCol().getConf().getString("sortType");
    for (int c = 0; c < fSortTypes.length; ++c) {
        if (fSortTypes[c].equals(colOrder)) {
            mOrder = c;
            break;
        }
    }
    if (mOrder == 1 && preferences.getBoolean("cardBrowserNoSorting", false)) {
        mOrder = 0;
    }
    // This upgrade should already have been done during
    // setConf. However older version of AnkiDroid didn't call
    // upgradeJSONIfNecessary during setConf, which means the
    // conf saved may still have this bug.
    mOrderAsc = Upgrade.upgradeJSONIfNecessary(getCol(), getCol().getConf(), "sortBackwards", false);
    mCards = new ArrayList<>();
    mCardsListView = (ListView) findViewById(R.id.card_browser_list);
    // Create a spinner for column1
    Spinner cardsColumn1Spinner = (Spinner) findViewById(R.id.browser_column1_spinner);
    ArrayAdapter<CharSequence> column1Adapter = ArrayAdapter.createFromResource(this, R.array.browser_column1_headings, android.R.layout.simple_spinner_item);
    column1Adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    cardsColumn1Spinner.setAdapter(column1Adapter);
    mColumn1Index = AnkiDroidApp.getSharedPrefs(getBaseContext()).getInt("cardBrowserColumn1", 0);
    cardsColumn1Spinner.setOnItemSelectedListener(new OnItemSelectedListener() {

        @Override
        public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
            // If a new column was selected then change the key used to map from mCards to the column TextView
            if (pos != mColumn1Index) {
                mColumn1Index = pos;
                AnkiDroidApp.getSharedPrefs(AnkiDroidApp.getInstance().getBaseContext()).edit().putInt("cardBrowserColumn1", mColumn1Index).commit();
                Column[] fromMap = mCardsAdapter.getFromMapping();
                fromMap[0] = COLUMN1_KEYS[mColumn1Index];
                mCardsAdapter.setFromMapping(fromMap);
            }
        }

        @Override
        public void onNothingSelected(AdapterView<?> parent) {
        // Do Nothing
        }
    });
    // Load default value for column2 selection
    mColumn2Index = AnkiDroidApp.getSharedPrefs(getBaseContext()).getInt("cardBrowserColumn2", 0);
    // Setup the column 2 heading as a spinner so that users can easily change the column type
    Spinner cardsColumn2Spinner = (Spinner) findViewById(R.id.browser_column2_spinner);
    ArrayAdapter<CharSequence> column2Adapter = ArrayAdapter.createFromResource(this, R.array.browser_column2_headings, android.R.layout.simple_spinner_item);
    column2Adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    cardsColumn2Spinner.setAdapter(column2Adapter);
    // Create a new list adapter with updated column map any time the user changes the column
    cardsColumn2Spinner.setOnItemSelectedListener(new OnItemSelectedListener() {

        @Override
        public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
            // If a new column was selected then change the key used to map from mCards to the column TextView
            if (pos != mColumn2Index) {
                mColumn2Index = pos;
                AnkiDroidApp.getSharedPrefs(AnkiDroidApp.getInstance().getBaseContext()).edit().putInt("cardBrowserColumn2", mColumn2Index).commit();
                Column[] fromMap = mCardsAdapter.getFromMapping();
                fromMap[1] = COLUMN2_KEYS[mColumn2Index];
                mCardsAdapter.setFromMapping(fromMap);
            }
        }

        @Override
        public void onNothingSelected(AdapterView<?> parent) {
        // Do Nothing
        }
    });
    // get the font and font size from the preferences
    int sflRelativeFontSize = preferences.getInt("relativeCardBrowserFontSize", DEFAULT_FONT_SIZE_RATIO);
    String sflCustomFont = preferences.getString("browserEditorFont", "");
    Column[] columnsContent = { COLUMN1_KEYS[mColumn1Index], COLUMN2_KEYS[mColumn2Index] };
    // make a new list adapter mapping the data in mCards to column1 and column2 of R.layout.card_item_browser
    mCardsAdapter = new MultiColumnListAdapter(this, R.layout.card_item_browser, columnsContent, new int[] { R.id.card_sfld, R.id.card_column2 }, sflRelativeFontSize, sflCustomFont);
    // link the adapter to the main mCardsListView
    mCardsListView.setAdapter(mCardsAdapter);
    // make the items (e.g. question & answer) render dynamically when scrolling
    mCardsListView.setOnScrollListener(new RenderOnScroll());
    // set the spinner index
    cardsColumn1Spinner.setSelection(mColumn1Index);
    cardsColumn2Spinner.setSelection(mColumn2Index);
    mCardsListView.setOnItemClickListener(new ListView.OnItemClickListener() {

        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
            if (mInMultiSelectMode) {
                // click on whole cell triggers select
                CheckBox cb = (CheckBox) view.findViewById(R.id.card_checkbox);
                cb.toggle();
                onCheck(position, view);
            } else {
                // load up the card selected on the list
                long clickedCardId = getCards().get(position).getId();
                openNoteEditorForCard(clickedCardId);
            }
        }
    });
    mCardsListView.setOnItemLongClickListener(new ListView.OnItemLongClickListener() {

        @Override
        public boolean onItemLongClick(AdapterView<?> adapterView, View view, final int position, long id) {
            mLastSelectedPosition = position;
            loadMultiSelectMode();
            // click on whole cell triggers select
            CheckBox cb = (CheckBox) view.findViewById(R.id.card_checkbox);
            cb.toggle();
            onCheck(position, view);
            recenterListView(view);
            mCardsAdapter.notifyDataSetChanged();
            return true;
        }
    });
    getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
    // If a valid value for last deck exists then use it, otherwise use libanki selected deck
    if (getLastDeckId() != null && getLastDeckId() == ALL_DECKS_ID) {
        selectAllDecks();
    } else if (getLastDeckId() != null && getCol().getDecks().get(getLastDeckId(), false) != null) {
        selectDeckById(getLastDeckId());
    } else {
        selectDeckById(getCol().getDecks().selected());
    }
}
Also used : SharedPreferences(android.content.SharedPreferences) Spinner(android.widget.Spinner) View(android.view.View) AdapterView(android.widget.AdapterView) SearchView(androidx.appcompat.widget.SearchView) TextView(android.widget.TextView) ListView(android.widget.ListView) AbsListView(android.widget.AbsListView) DeckDropDownAdapter(com.ichi2.anki.widgets.DeckDropDownAdapter) ListView(android.widget.ListView) AbsListView(android.widget.AbsListView) Column(com.ichi2.anki.CardBrowser.Column) CheckBox(android.widget.CheckBox) OnItemSelectedListener(android.widget.AdapterView.OnItemSelectedListener) ActionBar(androidx.appcompat.app.ActionBar) Toolbar(androidx.appcompat.widget.Toolbar)

Example 15 with Upgrade

use of com.ichi2.upgrade.Upgrade in project AnkiChinaAndroid by ankichinateam.

the class Syncer method sanityCheck.

public JSONObject sanityCheck() {
    JSONObject result = new JSONObject();
    try {
        if (mCol.getDb().queryScalar("SELECT count() FROM cards WHERE nid NOT IN (SELECT id FROM notes)") != 0) {
            Timber.e("Sync - SanityCheck: there are cards without mother notes");
            result.put("client", "missing notes");
            return result;
        }
        if (mCol.getDb().queryScalar("SELECT count() FROM notes WHERE id NOT IN (SELECT DISTINCT nid FROM cards)") != 0) {
            Timber.e("Sync - SanityCheck: there are notes without cards");
            result.put("client", "missing cards");
            return result;
        }
        if (mCol.getDb().queryScalar("SELECT count() FROM cards WHERE usn = -1") != 0) {
            Timber.e("Sync - SanityCheck: there are unsynced cards");
            result.put("client", "cards had usn = -1");
            return result;
        }
        if (mCol.getDb().queryScalar("SELECT count() FROM notes WHERE usn = -1") != 0) {
            Timber.e("Sync - SanityCheck: there are unsynced notes");
            result.put("client", "notes had usn = -1");
            return result;
        }
        if (mCol.getDb().queryScalar("SELECT count() FROM revlog WHERE usn = -1") != 0) {
            Timber.e("Sync - SanityCheck: there are unsynced revlogs");
            result.put("client", "revlog had usn = -1");
            return result;
        }
        if (mCol.getDb().queryScalar("SELECT count() FROM graves WHERE usn = -1") != 0) {
            Timber.e("Sync - SanityCheck: there are unsynced graves");
            result.put("client", "graves had usn = -1");
            return result;
        }
        for (Deck g : mCol.getDecks().all()) {
            if (g.getInt("usn") == -1) {
                Timber.e("Sync - SanityCheck: unsynced deck: " + g.getString("name"));
                result.put("client", "deck had usn = -1");
                return result;
            }
        }
        for (Map.Entry<String, Integer> tag : mCol.getTags().allItems()) {
            if (tag.getValue() == -1) {
                Timber.e("Sync - SanityCheck: there are unsynced tags");
                result.put("client", "tag had usn = -1");
                return result;
            }
        }
        boolean found = false;
        for (JSONObject m : mCol.getModels().all()) {
            if (mCol.getServer()) {
                // the web upgrade was mistakenly setting usn
                if (m.getInt("usn") < 0) {
                    m.put("usn", 0);
                    found = true;
                }
            } else {
                if (m.getInt("usn") == -1) {
                    Timber.e("Sync - SanityCheck: unsynced model: " + m.getString("name"));
                    result.put("client", "model had usn = -1");
                    return result;
                }
            }
        }
        if (found) {
            mCol.getModels().save();
        }
        // check for missing parent decks
        mCol.getSched().deckDueList();
        // return summary of deck
        JSONArray check = new JSONArray();
        JSONArray counts = new JSONArray();
        // #5666 - not in libAnki
        // We modified mReportLimit inside the scheduler, and this causes issues syncing dynamic decks.
        AbstractSched syncScheduler = mCol.createScheduler(SYNC_SCHEDULER_REPORT_LIMIT);
        for (int c : syncScheduler.recalculateCounts()) {
            counts.put(c);
        }
        check.put(counts);
        check.put(mCol.getDb().queryScalar("SELECT count() FROM cards"));
        check.put(mCol.getDb().queryScalar("SELECT count() FROM notes"));
        check.put(mCol.getDb().queryScalar("SELECT count() FROM revlog"));
        check.put(mCol.getDb().queryScalar("SELECT count() FROM graves"));
        check.put(mCol.getModels().all().size());
        check.put(mCol.getDecks().all().size());
        check.put(mCol.getDecks().allConf().size());
        result.put("client", check);
        return result;
    } catch (JSONException e) {
        Timber.e(e, "Syncer.sanityCheck()");
        throw new RuntimeException(e);
    }
}
Also used : JSONObject(com.ichi2.utils.JSONObject) AbstractSched(com.ichi2.libanki.sched.AbstractSched) JSONArray(com.ichi2.utils.JSONArray) Deck(com.ichi2.libanki.Deck) JSONException(com.ichi2.utils.JSONException) HashMap(java.util.HashMap) Map(java.util.Map)

Aggregations

File (java.io.File)7 Intent (android.content.Intent)6 SharedPreferences (android.content.SharedPreferences)6 View (android.view.View)6 Resources (android.content.res.Resources)5 Bundle (android.os.Bundle)5 TextView (android.widget.TextView)5 Collection (com.ichi2.libanki.Collection)5 JSONException (com.ichi2.utils.JSONException)5 SQLiteDatabaseCorruptException (android.database.sqlite.SQLiteDatabaseCorruptException)4 Message (android.os.Message)4 NonNull (androidx.annotation.NonNull)4 SearchView (androidx.appcompat.widget.SearchView)4 ConfirmModSchemaException (com.ichi2.anki.exception.ConfirmModSchemaException)4 FileInputStream (java.io.FileInputStream)4 FileNotFoundException (java.io.FileNotFoundException)4 IOException (java.io.IOException)4 InputStream (java.io.InputStream)4 List (java.util.List)4 BroadcastReceiver (android.content.BroadcastReceiver)3