Search in sources :

Example 16 with DeckPicker

use of com.ichi2.anki.DeckPicker in project AnkiChinaAndroid by ankichinateam.

the class DialogHandler method handleMessage.

@Override
public void handleMessage(Message msg) {
    Bundle msgData = msg.getData();
    String messageName = sMessageNameList[msg.what];
    UsageAnalytics.sendAnalyticsScreenView(messageName);
    Timber.i("Handling Message: %s", messageName);
    if (msg.what == MSG_SHOW_COLLECTION_LOADING_ERROR_DIALOG) {
        // Collection could not be opened
        mActivity.get().showDatabaseErrorDialog(DatabaseErrorDialog.DIALOG_LOAD_FAILED);
    } else if (msg.what == MSG_SHOW_COLLECTION_IMPORT_REPLACE_DIALOG) {
        // Handle import of collection package APKG
        mActivity.get().showImportDialog(ImportDialog.DIALOG_IMPORT_REPLACE_CONFIRM, msgData.getString("importPath"));
    } else if (msg.what == MSG_SHOW_COLLECTION_IMPORT_ADD_DIALOG) {
        // Handle import of deck package APKG
        mActivity.get().showImportDialog(ImportDialog.DIALOG_IMPORT_ADD_CONFIRM, msgData.getString("importPath"));
    } else if (msg.what == MSG_SHOW_SYNC_ERROR_DIALOG) {
        if (mActivity.get() instanceof DeckPicker) {
            int id = msgData.getInt("dialogType");
            String message = msgData.getString("dialogMessage");
            ((DeckPicker) mActivity.get()).showSyncErrorDialog(id, message);
        }
    } else if (msg.what == MSG_SHOW_EXPORT_COMPLETE_DIALOG) {
        // Export complete
        AsyncDialogFragment f = DeckPickerExportCompleteDialog.newInstance(msgData.getString("exportPath"));
        mActivity.get().showAsyncDialogFragment(f);
    } else if (msg.what == MSG_SHOW_MEDIA_CHECK_COMPLETE_DIALOG) {
        if (mActivity.get() instanceof DeckPicker) {
            // Media check results
            int id = msgData.getInt("dialogType");
            if (id != MediaCheckDialog.DIALOG_CONFIRM_MEDIA_CHECK) {
                List<List<String>> checkList = new ArrayList<>();
                checkList.add(msgData.getStringArrayList("nohave"));
                checkList.add(msgData.getStringArrayList("unused"));
                checkList.add(msgData.getStringArrayList("invalid"));
                ((DeckPicker) mActivity.get()).showMediaCheckDialog(id, checkList);
            }
        }
    } else if (msg.what == MSG_SHOW_DATABASE_ERROR_DIALOG) {
        // Database error dialog
        mActivity.get().showDatabaseErrorDialog(msgData.getInt("dialogType"));
    } else if (msg.what == MSG_SHOW_FORCE_FULL_SYNC_DIALOG) {
        // Confirmation dialog for forcing full sync
        ConfirmationDialog dialog = new ConfirmationDialog();
        Runnable confirm = new Runnable() {

            @Override
            public void run() {
                // Bypass the check once the user confirms
                CollectionHelper.getInstance().getCol(AnkiDroidApp.getInstance()).modSchemaNoCheck();
            }
        };
        dialog.setConfirm(confirm);
        dialog.setArgs(msgData.getString("message"));
        (mActivity.get()).showDialogFragment(dialog);
    } else if (msg.what == MSG_DO_SYNC) {
        if (mActivity.get() instanceof DeckPicker) {
            SharedPreferences preferences = AnkiDroidApp.getSharedPrefs(mActivity.get());
            Resources res = mActivity.get().getResources();
            Collection col = mActivity.get().getCol();
            String hkey = preferences.getString("hkey", "");
            long millisecondsSinceLastSync = col.getTime().intTimeMS() - preferences.getLong("lastSyncTime", 0);
            boolean limited = millisecondsSinceLastSync < INTENT_SYNC_MIN_INTERVAL;
            if (!limited && hkey.length() > 0 && Connection.isOnline()) {
                ((DeckPicker) mActivity.get()).sync();
            } else {
                String err = res.getString(R.string.sync_error);
                if (limited) {
                    long remainingTimeInSeconds = Math.max((INTENT_SYNC_MIN_INTERVAL - millisecondsSinceLastSync) / 1000, 1);
                    // getQuantityString needs an int
                    int remaining = (int) Math.min(Integer.MAX_VALUE, remainingTimeInSeconds);
                    String message = res.getQuantityString(R.plurals.sync_automatic_sync_needs_more_time, remaining, remaining);
                    mActivity.get().showSimpleNotification(err, message, NotificationChannels.Channel.SYNC);
                } else {
                    mActivity.get().showSimpleNotification(err, res.getString(R.string.youre_offline), NotificationChannels.Channel.SYNC);
                }
            }
            mActivity.get().finishWithoutAnimation();
        }
    }
}
Also used : SharedPreferences(android.content.SharedPreferences) Bundle(android.os.Bundle) Collection(com.ichi2.libanki.Collection) ArrayList(java.util.ArrayList) List(java.util.List) Resources(android.content.res.Resources) DeckPicker(com.ichi2.anki.DeckPicker)

Example 17 with DeckPicker

use of com.ichi2.anki.DeckPicker in project Anki-Android by ankidroid.

the class IntentHandler method handleFileImport.

private void handleFileImport(Intent intent, Intent reloadIntent, String action) {
    Timber.i("Handling file import");
    ImportResult importResult = ImportUtils.handleFileImport(this, intent);
    // Start DeckPicker if we correctly processed ACTION_VIEW
    if (importResult.isSuccess()) {
        Timber.d("onCreate() import successful");
        reloadIntent.setAction(action);
        reloadIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        startActivity(reloadIntent);
        AnkiActivity.finishActivityWithFade(this);
    } else {
        Timber.i("File import failed");
        // Don't import the file if it didn't load properly or doesn't have apkg extension
        ImportUtils.showImportUnsuccessfulDialog(this, importResult.getHumanReadableMessage(), true);
    }
}
Also used : ImportResult(com.ichi2.utils.ImportUtils.ImportResult)

Example 18 with DeckPicker

use of com.ichi2.anki.DeckPicker in project Anki-Android by ankidroid.

the class DeckPicker method showStartupScreensAndDialogs.

private void showStartupScreensAndDialogs(SharedPreferences preferences, int skip) {
    // For Android 8/8.1 we want to use software rendering by default or the Reviewer UI is broken #7369
    if (CompatHelper.getSdkVersion() == Build.VERSION_CODES.O || CompatHelper.getSdkVersion() == Build.VERSION_CODES.O_MR1) {
        if (!preferences.contains("softwareRender")) {
            Timber.i("Android 8/8.1 detected with no render preference. Turning on software render.");
            preferences.edit().putBoolean("softwareRender", true).apply();
        } else {
            Timber.i("Android 8/8.1 detected, software render preference already exists.");
        }
    }
    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 (InitialActivity.performSetupFromFreshInstallOrClearedPreferences(preferences)) {
        onFinishedStartup();
    } else if (skip < 2 && !InitialActivity.isLatestVersion(preferences)) {
        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)) {
            displayAnalyticsOptInDialog();
        }
        // 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 {
                ModelManager 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 upgradeDbVersion = AnkiDroidApp.CHECK_DB_AT_VERSION;
        // Specifying a checkpoint in the future is not supported, please don't do it!
        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;
        // if (previous < upgradeDbVersion && getCol().basicCheck()) {
        // skipDbCheck = true;
        // }
        boolean upgradedPreferences = InitialActivity.upgradePreferences(this, 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.check_db).negativeText(R.string.close).onPositive((materialDialog, dialogAction) -> integrityCheck()).onNeutral((materialDialog, dialogAction) -> restartActivity()).onNegative((materialDialog, dialogAction) -> restartActivity()).canceledOnTouchOutside(false).cancelable(false).build().show();
            return;
        }
        if (upgradedPreferences) {
            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
            restartActivity();
            return;
        }
        // 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, START);
            } 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
            InitialActivity.setUpgradedToLatestVersion(preferences);
            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 : DividerItemDecoration(androidx.recyclerview.widget.DividerItemDecoration) StartupFailure(com.ichi2.anki.InitialActivity.StartupFailure) Bundle(android.os.Bundle) NonNull(androidx.annotation.NonNull) Uri(android.net.Uri) DialogHandler(com.ichi2.anki.dialogs.DialogHandler) Drawable(android.graphics.drawable.Drawable) ShortcutManagerCompat(androidx.core.content.pm.ShortcutManagerCompat) Manifest(android.Manifest) Decks(com.ichi2.libanki.Decks) Fragment(androidx.fragment.app.Fragment) JSONException(com.ichi2.utils.JSONException) ContextCompat(androidx.core.content.ContextCompat) DeckPickerBackupNoSpaceLeftDialog(com.ichi2.anki.dialogs.DeckPickerBackupNoSpaceLeftDialog) IntentFilter(android.content.IntentFilter) Triple(com.ichi2.utils.Triple) SearchView(androidx.appcompat.widget.SearchView) DeckPickerContextMenu(com.ichi2.anki.dialogs.DeckPickerContextMenu) Cancellable(com.ichi2.async.Cancellable) DeckRenameException(com.ichi2.libanki.backend.exception.DeckRenameException) StringRes(androidx.annotation.StringRes) Unit(kotlin.Unit) Nullable(androidx.annotation.Nullable) Message(android.os.Message) HostNumFactory(com.ichi2.anki.web.HostNumFactory) CompatHelper(com.ichi2.compat.CompatHelper) DeckAdapter(com.ichi2.anki.widgets.DeckAdapter) LinearLayoutManager(androidx.recyclerview.widget.LinearLayoutManager) DeckPickerNoSpaceToDowngradeDialog(com.ichi2.anki.dialogs.DeckPickerNoSpaceToDowngradeDialog) DeckPickerConfirmDeleteDeckDialog(com.ichi2.anki.dialogs.DeckPickerConfirmDeleteDeckDialog) Direction(com.ichi2.anim.ActivityTransitionAnimation.Direction) FULL_DOWNLOAD(com.ichi2.async.Connection.ConflictResolution.FULL_DOWNLOAD) SdCardReceiver(com.ichi2.anki.receiver.SdCardReceiver) Editor(android.content.SharedPreferences.Editor) CustomSyncServerUrlException(com.ichi2.libanki.sync.CustomSyncServerUrlException) FileSizeFormatter(com.ichi2.anki.dialogs.DeckPickerNoSpaceToDowngradeDialog.FileSizeFormatter) DeckPickerNoSpaceLeftDialog(com.ichi2.anki.dialogs.DeckPickerNoSpaceLeftDialog) StudyOptionsListener(com.ichi2.anki.StudyOptionsFragment.StudyOptionsListener) BadgeDrawableBuilder(com.ichi2.ui.BadgeDrawableBuilder) Menu(android.view.Menu) DeckService(com.ichi2.anki.servicelayer.DeckService) Connection(com.ichi2.async.Connection) Settings(android.provider.Settings) AnkiPackageImporter(com.ichi2.libanki.importer.AnkiPackageImporter) SwipeRefreshLayout(androidx.swiperefreshlayout.widget.SwipeRefreshLayout) CollectionIntegrityStorageCheck(com.ichi2.anki.CollectionHelper.CollectionIntegrityStorageCheck) ActivityExportingDelegate(com.ichi2.anki.export.ActivityExportingDelegate) TextUtils(android.text.TextUtils) File(java.io.File) SharedPreferences(android.content.SharedPreferences) TypedValue(android.util.TypedValue) IconCompat(androidx.core.graphics.drawable.IconCompat) ImportUtils(com.ichi2.utils.ImportUtils) EditText(android.widget.EditText) SchedulerService(com.ichi2.anki.servicelayer.SchedulerService) LinearLayout(android.widget.LinearLayout) AsyncDialogFragment(com.ichi2.anki.dialogs.AsyncDialogFragment) PackageManager(android.content.pm.PackageManager) TaskManager(com.ichi2.async.TaskManager) WindowManager(android.view.WindowManager) UsageAnalytics(com.ichi2.anki.analytics.UsageAnalytics) ModelManager(com.ichi2.libanki.ModelManager) ConfirmationDialog(com.ichi2.anki.dialogs.ConfirmationDialog) AnkiStatsTaskHandler(com.ichi2.anki.stats.AnkiStatsTaskHandler) Permissions(com.ichi2.utils.Permissions) View(android.view.View) RecyclerView(androidx.recyclerview.widget.RecyclerView) SyncStatus(com.ichi2.utils.SyncStatus) FragmentTransaction(androidx.fragment.app.FragmentTransaction) BroadcastReceiver(android.content.BroadcastReceiver) DatabaseErrorDialog(com.ichi2.anki.dialogs.DatabaseErrorDialog) CustomStudyDialogFactory(com.ichi2.anki.dialogs.customstudy.CustomStudyDialogFactory) Timber(timber.log.Timber) UndoService(com.ichi2.anki.servicelayer.UndoService) List(java.util.List) TextView(android.widget.TextView) ImportFileSelectionFragment(com.ichi2.anki.dialogs.ImportFileSelectionFragment) RelativeLayout(android.widget.RelativeLayout) Filterable(android.widget.Filterable) TaskListenerWithContext(com.ichi2.async.TaskListenerWithContext) ViewPropertyAnimator(android.view.ViewPropertyAnimator) MaterialDialog(com.afollestad.materialdialogs.MaterialDialog) Snackbar(com.google.android.material.snackbar.Snackbar) Window(android.view.Window) VersionUtils(com.ichi2.utils.VersionUtils) Context(android.content.Context) TaskListener(com.ichi2.async.TaskListener) KeyEvent(android.view.KeyEvent) GravityEnum(com.afollestad.materialdialogs.GravityEnum) Pair(android.util.Pair) DeckPickerAnalyticsOptInDialog(com.ichi2.anki.dialogs.DeckPickerAnalyticsOptInDialog) ImportDialog(com.ichi2.anki.dialogs.ImportDialog) Intent(android.content.Intent) Collection(com.ichi2.libanki.Collection) StyledProgressDialog(com.ichi2.themes.StyledProgressDialog) PixelFormat(android.graphics.PixelFormat) TypedArray(android.content.res.TypedArray) MenuItem(android.view.MenuItem) WidgetStatus(com.ichi2.widget.WidgetStatus) SyncErrorDialog(com.ichi2.anki.dialogs.SyncErrorDialog) Payload(com.ichi2.async.Connection.Payload) Model(com.ichi2.libanki.Model) Build(android.os.Build) ShortcutInfoCompat(androidx.core.content.pm.ShortcutInfoCompat) Utils(com.ichi2.libanki.Utils) DialogInterface(android.content.DialogInterface) ConfirmModSchemaException(com.ichi2.anki.exception.ConfirmModSchemaException) Computation(com.ichi2.utils.Computation) AbstractDeckTreeNode(com.ichi2.libanki.sched.AbstractDeckTreeNode) ActivityCompat(androidx.core.app.ActivityCompat) CreateDeckDialog(com.ichi2.anki.dialogs.CreateDeckDialog) CollectionTask(com.ichi2.async.CollectionTask) SQLException(android.database.SQLException) CustomStudyDialog(com.ichi2.anki.dialogs.customstudy.CustomStudyDialog) Syncer(com.ichi2.libanki.sync.Syncer) MediaCheckDialog(com.ichi2.anki.dialogs.MediaCheckDialog) AdaptionUtil(com.ichi2.utils.AdaptionUtil) VisibleForTesting(androidx.annotation.VisibleForTesting) Resources(android.content.res.Resources) OnClickListener(android.view.View.OnClickListener) BadgeDrawableBuilder(com.ichi2.ui.BadgeDrawableBuilder) Model(com.ichi2.libanki.Model) JSONException(com.ichi2.utils.JSONException) Intent(android.content.Intent) ModelManager(com.ichi2.libanki.ModelManager) File(java.io.File)

Example 19 with DeckPicker

use of com.ichi2.anki.DeckPicker in project Anki-Android by ankidroid.

the class DeckPickerImportTest method replaceShowsImportDialog.

@Test
public void replaceShowsImportDialog() {
    DeckPickerImport deckPicker = super.startActivityNormallyOpenCollectionWithIntent(DeckPickerImport.class, new Intent());
    deckPicker.showImportDialog(ImportDialog.DIALOG_IMPORT_REPLACE_CONFIRM, "");
    assertThat(deckPicker.getAsyncDialogFragmentClass(), Matchers.typeCompatibleWith(ImportDialog.class));
}
Also used : ImportDialog(com.ichi2.anki.dialogs.ImportDialog) Intent(android.content.Intent) Test(org.junit.Test)

Example 20 with DeckPicker

use of com.ichi2.anki.DeckPicker in project Anki-Android by ankidroid.

the class DeckPickerTest method deletion_of_filtered_deck_shows_warning_issue_10238.

@Test
public void deletion_of_filtered_deck_shows_warning_issue_10238() {
    // Filtered decks contain their own options, deleting one can cause a significant loss of work.
    // And they are more likely to be empty temporarily
    long did = addDynamicDeck("filtered");
    DeckPicker deckPicker = startActivityNormallyOpenCollectionWithIntent(DeckPicker.class, new Intent());
    deckPicker.confirmDeckDeletion(did);
    DialogFragment fragment = AnkiActivityUtils.getDialogFragment(deckPicker);
    assertThat("deck deletion confirmation window should be shown", fragment, instanceOf(DeckPickerConfirmDeleteDeckDialog.class));
}
Also used : DialogFragment(androidx.fragment.app.DialogFragment) Intent(android.content.Intent) DeckPickerConfirmDeleteDeckDialog(com.ichi2.anki.dialogs.DeckPickerConfirmDeleteDeckDialog) Test(org.junit.Test)

Aggregations

Intent (android.content.Intent)11 Resources (android.content.res.Resources)10 Bundle (android.os.Bundle)10 MaterialDialog (com.afollestad.materialdialogs.MaterialDialog)8 Collection (com.ichi2.libanki.Collection)8 SharedPreferences (android.content.SharedPreferences)7 View (android.view.View)6 TextView (android.widget.TextView)6 Context (android.content.Context)5 TypedArray (android.content.res.TypedArray)5 Drawable (android.graphics.drawable.Drawable)5 Menu (android.view.Menu)5 HostNumFactory (com.ichi2.anki.web.HostNumFactory)5 List (java.util.List)5 Window (android.view.Window)4 WindowManager (android.view.WindowManager)4 RelativeLayout (android.widget.RelativeLayout)4 NonNull (androidx.annotation.NonNull)4 Nullable (androidx.annotation.Nullable)4 ArrayList (java.util.ArrayList)4