Search in sources :

Example 1 with START

use of com.ichi2.anim.ActivityTransitionAnimation.Direction.START in project AnkiChinaAndroid by ankichinateam.

the class NoteEditor method setMMButtonListener.

private void setMMButtonListener(ImageButton mediaButton, final int index) {
    mediaButton.setOnClickListener(v -> {
        Timber.i("NoteEditor:: Multimedia button pressed for field %d", index);
        if (mEditorNote.items()[index][1].length() > 0) {
            final Collection col = CollectionHelper.getInstance().getCol(NoteEditor.this);
            // If the field already exists then we start the field editor, which figures out the type
            // automatically
            IMultimediaEditableNote mNote = getCurrentMultimediaEditableNote(col);
            startMultimediaFieldEditor(index, mNote);
        } else {
            // Otherwise we make a popup menu allowing the user to choose between audio/image/text field
            // TODO: Update the icons for dark material theme, then can set 3rd argument to true
            PopupMenuWithIcons popup = new PopupMenuWithIcons(NoteEditor.this, v, false);
            MenuInflater inflater = popup.getMenuInflater();
            inflater.inflate(R.menu.popupmenu_multimedia_options, popup.getMenu());
            popup.setOnMenuItemClickListener(item -> {
                int itemId = item.getItemId();
                if (itemId == R.id.menu_multimedia_audio) {
                    Timber.i("NoteEditor:: Record audio button pressed");
                    startMultimediaFieldEditorForField(index, new AudioRecordingField());
                    return true;
                } else if (itemId == R.id.menu_multimedia_audio_clip) {
                    Timber.i("NoteEditor:: Add audio clip button pressed");
                    startMultimediaFieldEditorForField(index, new AudioClipField());
                    return true;
                } else if (itemId == R.id.menu_multimedia_photo) {
                    Timber.i("NoteEditor:: Add image button pressed");
                    startMultimediaFieldEditorForField(index, new ImageField());
                    return true;
                } else if (itemId == R.id.menu_multimedia_text) {
                    Timber.i("NoteEditor:: Advanced editor button pressed");
                    startAdvancedTextEditor(index);
                    return true;
                } else if (itemId == R.id.menu_multimedia_clear_field) {
                    Timber.i("NoteEditor:: Clear field button pressed");
                    clearField(index);
                }
                return false;
            });
            if (AdaptionUtil.isRestrictedLearningDevice()) {
                popup.getMenu().findItem(R.id.menu_multimedia_photo).setVisible(false);
                popup.getMenu().findItem(R.id.menu_multimedia_text).setVisible(false);
            }
            popup.show();
        }
    });
}
Also used : ImageField(com.ichi2.anki.multimediacard.fields.ImageField) MenuInflater(android.view.MenuInflater) PopupMenuWithIcons(com.ichi2.anki.widgets.PopupMenuWithIcons) AudioClipField(com.ichi2.anki.multimediacard.fields.AudioClipField) Collection(com.ichi2.libanki.Collection) IMultimediaEditableNote(com.ichi2.anki.multimediacard.IMultimediaEditableNote) SuppressLint(android.annotation.SuppressLint) AudioRecordingField(com.ichi2.anki.multimediacard.fields.AudioRecordingField)

Example 2 with START

use of com.ichi2.anim.ActivityTransitionAnimation.Direction.START in project AnkiChinaAndroid by ankichinateam.

the class AnkiDroidApp method onCreate.

/**
 * On application creation.
 */
@Override
public void onCreate() {
    super.onCreate();
    registerActivityLifecycleCallbacks(activityLifecycleCallbacks);
    if (sInstance != null) {
        Timber.i("onCreate() called multiple times");
        // 5887 - fix crash.
        if (sInstance.getResources() == null) {
            Timber.w("Skipping re-initialisation - no resources. Maybe uninstalling app?");
            return;
        }
    }
    sInstance = this;
    // Get preferences
    SharedPreferences preferences = getSharedPrefs(this);
    Consts.LOGIN_SERVER = preferences.getInt(Consts.KEY_ANKI_ACCOUNT_SERVER, 0);
    // Setup logging and crash reporting
    acraCoreConfigBuilder = new CoreConfigurationBuilder(this);
    if (BuildConfig.DEBUG) {
        // Enable verbose error logging and do method tracing to put the Class name as log tag
        Timber.plant(new DebugTree());
        setDebugACRAConfig(preferences);
    } else {
        Timber.plant(new ProductionCrashReportingTree());
        setProductionACRAConfig(preferences);
    }
    Timber.tag(TAG);
    Timber.d("Startup - Application Start");
    // Analytics falls back to a sensible default if this is not set.
    if (ACRA.isACRASenderServiceProcess() && Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
        try {
            WebViewDebugging.setDataDirectorySuffix("acra");
        } catch (Exception e) {
            Timber.w(e, "Failed to set WebView data directory");
        }
    }
    // analytics after ACRA, they both install UncaughtExceptionHandlers but Analytics chains while ACRA does not
    UsageAnalytics.initialize(this);
    if (BuildConfig.DEBUG) {
        UsageAnalytics.setDryRun(true);
    }
    // Stop after analytics and logging are initialised.
    if (ACRA.isACRASenderServiceProcess()) {
        Timber.d("Skipping AnkiDroidApp.onCreate from ACRA sender process");
        return;
    }
    if (AdaptionUtil.isUserATestClient()) {
        UIUtils.showThemedToast(this.getApplicationContext(), getString(R.string.user_is_a_robot), false);
    }
    CardBrowserContextMenu.ensureConsistentStateWithSharedPreferences(this);
    AnkiCardContextMenu.ensureConsistentStateWithSharedPreferences(this);
    NotificationChannels.setup(getApplicationContext());
    // Configure WebView to allow file scheme pages to access cookies.
    CookieManager.setAcceptFileSchemeCookies(true);
    // Prepare Cookies to be synchronized between RAM and permanent storage.
    CompatHelper.getCompat().prepareWebViewCookies(this.getApplicationContext());
    // Set good default values for swipe detection
    final ViewConfiguration vc = ViewConfiguration.get(this);
    DEFAULT_SWIPE_MIN_DISTANCE = vc.getScaledPagingTouchSlop();
    DEFAULT_SWIPE_THRESHOLD_VELOCITY = vc.getScaledMinimumFlingVelocity();
    // Forget the last deck that was used in the CardBrowser
    CardBrowser.clearLastDeckId();
    // Create the AnkiDroid directory if missing. Send exception report if inaccessible.
    if (Permissions.hasStorageAccessPermission(this)) {
        try {
            String dir = CollectionHelper.getCurrentAnkiDroidDirectory(this);
            CollectionHelper.initializeAnkiDroidDirectory(dir);
        } catch (StorageAccessException e) {
            Timber.e(e, "Could not initialize AnkiDroid directory");
            String defaultDir = CollectionHelper.getDefaultAnkiDroidDirectory();
            if (isSdCardMounted() && CollectionHelper.getCurrentAnkiDroidDirectory(this).equals(defaultDir)) {
                // Don't send report if the user is using a custom directory as SD cards trip up here a lot
                sendExceptionReport(e, "AnkiDroidApp.onCreate");
            }
        }
    }
    Timber.i("AnkiDroidApp: Starting Services");
    new BootService().onReceive(this, new Intent(this, BootService.class));
    // Register BroadcastReceiver NotificationService
    NotificationService ns = new NotificationService();
    LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(this);
    lbm.registerReceiver(ns, new IntentFilter(NotificationService.INTENT_ACTION));
}
Also used : IntentFilter(android.content.IntentFilter) SharedPreferences(android.content.SharedPreferences) StorageAccessException(com.ichi2.anki.exception.StorageAccessException) Intent(android.content.Intent) NotificationService(com.ichi2.anki.services.NotificationService) LocalBroadcastManager(androidx.localbroadcastmanager.content.LocalBroadcastManager) ManuallyReportedException(com.ichi2.anki.exception.ManuallyReportedException) StorageAccessException(com.ichi2.anki.exception.StorageAccessException) CoreConfigurationBuilder(org.acra.config.CoreConfigurationBuilder) DebugTree(timber.log.Timber.DebugTree) ViewConfiguration(android.view.ViewConfiguration) BootService(com.ichi2.anki.services.BootService)

Example 3 with START

use of com.ichi2.anim.ActivityTransitionAnimation.Direction.START in project AnkiChinaAndroid by ankichinateam.

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 4 with START

use of com.ichi2.anim.ActivityTransitionAnimation.Direction.START in project AnkiChinaAndroid by ankichinateam.

the class StudyOptionsFragment method getCollectionTaskListener.

/**
 * Returns a listener that rebuilds the interface after execute.
 *
 * @param refreshDecklist If true, the listener notifies the parent activity to update its deck list
 *                        to reflect the latest values.
 */
private TaskListener getCollectionTaskListener(final boolean refreshDecklist) {
    return new TaskListener() {

        @Override
        public void onPreExecute() {
        }

        @Override
        public void onPostExecute(TaskData result) {
            dismissProgressDialog();
            if (result != null) {
                // Get the return values back from the AsyncTask
                Object[] obj = result.getObjArray();
                int newCards = (Integer) obj[0];
                int lrnCards = (Integer) obj[1];
                int revCards = (Integer) obj[1] + (Integer) obj[2];
                int totalNew = (Integer) obj[3];
                int totalCards = (Integer) obj[4];
                Timber.i("start refresh list data:" + newCards + "," + lrnCards + "," + revCards + "," + totalNew + "," + totalCards);
                // Don't do anything if the fragment is no longer attached to it's Activity or col has been closed
                if (getActivity() == null) {
                    Timber.e("StudyOptionsFragment.mRefreshFragmentListener :: can't refresh");
                    return;
                }
                // #5506 If we have no view, short circuit all UI logic
                if (mStudyOptionsView == null) {
                    tryOpenCramDeckOptions();
                    return;
                }
                // Reinitialize controls incase changed to filtered deck
                initAllContentViews(mStudyOptionsView);
                // Set the deck name
                String fullName;
                Deck deck = getCol().getDecks().current();
                // Main deck name
                fullName = deck.getString("name");
                String[] name = Decks.path(fullName);
                StringBuilder nameBuilder = new StringBuilder();
                if (name.length > 0) {
                    nameBuilder.append(name[name.length - 1]);
                }
                // if (name.length > 1) {
                // nameBuilder.append("\n").append(name[1]);
                // }
                // if (name.length > 3) {
                // nameBuilder.append("...");
                // }
                // if (name.length > 2) {
                // nameBuilder.append("\n").append(name[name.length - 1]);
                // }
                // mTextDeckName.setText(nameBuilder.toString());
                mDeckListAdapter.mTextDeckName = nameBuilder.toString();
                if (tryOpenCramDeckOptions()) {
                    return;
                }
                // Switch between the empty view, the ordinary view, and the "congratulations" view
                boolean isDynamic = deck.optInt("dyn", 0) != 0;
                if (totalCards == 0 && !isDynamic) {
                    mCurrentContentView = CONTENT_EMPTY;
                    mDeckListAdapter.mDeckInfoLayoutVisible = View.VISIBLE;
                    mDeckListAdapter.mTextCongratsMessageVisible = View.VISIBLE;
                    // mDeckListAdapter.mTextCongratsMessage=getString(R.string.studyoptions_empty);
                    mDeckListAdapter.mButtonStartEnable = false;
                    mDeckListAdapter.mTextButtonStart = getString(R.string.studyoptions_start);
                } else if (newCards + lrnCards + revCards == 0) {
                    mCurrentContentView = CONTENT_CONGRATS;
                    if (!isDynamic) {
                        mDeckListAdapter.mDeckInfoLayoutVisible = View.GONE;
                        mDeckListAdapter.mButtonStartEnable = true;
                        mDeckListAdapter.mTextButtonStart = getString(R.string.add_today_study_amount);
                    } else {
                        mDeckListAdapter.mButtonStartEnable = true;
                        mDeckListAdapter.mTextButtonStart = getString(R.string.add_today_study_amount);
                    }
                    mDeckListAdapter.mTextCongratsMessageVisible = View.VISIBLE;
                // mDeckListAdapter.mTextCongratsMessage=getCol().getSched().finishedMsg(getActivity()).toString();
                // mTextCongratsMessage.setText(getCol().getSched().finishedMsg(getActivity()));
                } else {
                    mCurrentContentView = CONTENT_STUDY_OPTIONS;
                    mDeckListAdapter.mDeckInfoLayoutVisible = View.VISIBLE;
                    mDeckListAdapter.mTextCongratsMessageVisible = View.GONE;
                    mDeckListAdapter.mButtonStartEnable = true;
                    mDeckListAdapter.mTextButtonStart = getString(R.string.studyoptions_start);
                }
                mDeckListAdapter.setButtonStartClickListener(mButtonClickListener);
                mDeckListAdapter.setSelfStudyClickListener(mSelfStudyListener);
                // Set deck description
                String desc;
                if (isDynamic) {
                    desc = getResources().getString(R.string.dyn_deck_desc);
                } else {
                    desc = "";
                // desc = getCol().getDecks().getActualDescription();
                }
                if (desc.length() > 0) {
                    mDeckListAdapter.mTextDeckDescription = desc;
                    mDeckListAdapter.mTextDeckDescriptionVisible = View.VISIBLE;
                // mTextDeckDescription.setText(formatDescription(desc));
                // mTextDeckDescription.setVisibility(View.VISIBLE);
                } else {
                    mDeckListAdapter.mTextDeckDescriptionVisible = View.GONE;
                }
                // Set new/learn/review card counts
                mDeckListAdapter.mTextTodayNew = String.valueOf(newCards);
                mDeckListAdapter.mTextTodayRev = String.valueOf(revCards);
                // Set the total number of new cards in deck
                if (totalNew < NEW_CARD_COUNT_TRUNCATE_THRESHOLD) {
                // if it hasn't been truncated by libanki then just set it usually
                // mTextNewTotal.setText(String.valueOf(totalNew));
                } else {
                    // mTextNewTotal.setText(">1000");
                    if (mFullNewCountThread != null) {
                        // a thread was previously made -- interrupt it
                        mFullNewCountThread.interrupt();
                    }
                // mFullNewCountThread = new Thread(() -> {
                // Collection collection = getCol();
                // TODO: refactor code to not rewrite this query, add to Sched.totalNewForCurrentDeck()
                // String query = "SELECT count(*) FROM cards WHERE did IN " +
                // Utils.ids2str(collection.getDecks().active()) +
                // " AND queue = " + Consts.QUEUE_TYPE_NEW;
                // final int fullNewCount = collection.getDb().queryScalar(query);
                // if (fullNewCount > 0) {
                // Runnable setNewTotalText = new Runnable() {
                // @Override
                // public void run() {
                // mTextNewTotal.setText(String.valueOf(fullNewCount));
                // }
                // };
                // if (!Thread.currentThread().isInterrupted()) {
                // mTextNewTotal.post(setNewTotalText);
                // }
                // }
                // });
                // mFullNewCountThread.start();
                }
                // Set total number of cards
                // mTextTotal.setText(String.valueOf(totalCards));
                double[] data = calculateStat(getCol(), getCol().getDecks().current().optLong("id"));
                mNewCardsNum = (int) data[2];
                mRevCardsNum = revCards;
                mShouldConfigBeforeStudy = mNewCardsNum == totalCards && mShouldConfigBeforeStudy;
                int hardNum = getLapses(getCol(), getCol().getDecks().current().optLong("id"));
                mDeckListAdapter.mTextCountHandled = String.format(Locale.CHINA, "%d", (int) data[0]);
                mDeckListAdapter.mTextCountLearning = String.format(Locale.CHINA, "%d", (int) data[1]);
                mDeckListAdapter.mTextCountNew = String.format(Locale.CHINA, "%d", (int) data[2]);
                mDeckListAdapter.mTextCountHard = String.format(Locale.CHINA, "%d", hardNum);
                mDeckListAdapter.mTextTotal = String.format(Locale.CHINA, "共%d张卡牌", totalCards);
                double percent = 0;
                if (data[2] == 0) {
                    // 新卡已学完,显示已掌握
                    percent = (data[0] + data[1] + data[2] <= 0) ? 0 : (data[0] / (data[0] + data[1] + data[2]) * 100);
                    mDeckListAdapter.mTextHandledNum = String.format(Locale.CHINA, "%.0f/%.0f", data[0], (data[0] + data[1] + data[2]));
                // holder.handled_percent.setText((String.format(Locale.CHINA, "已掌握 %.1f", percent)) + "%");
                } else {
                    percent = (data[0] + data[1] + data[2] <= 0) ? 0 : ((data[0] + data[1]) / (data[0] + data[1] + data[2]) * 100);
                    mDeckListAdapter.mTextHandledNum = String.format(Locale.CHINA, "%.0f/%.0f", data[0] + data[1], data[0] + data[1] + data[2]);
                // holder.handled_percent.setText((String.format(Locale.CHINA, "已学 %.1f", percent)) + "%");
                }
                // double percent = (data[0] + data[1] + data[2] <= 0) ? 0 : (data[0] / (data[0] + data[1] + data[2]) * 100);
                // mStudyProgress.setMax(100*100);
                mDeckListAdapter.mStudyProgress = (int) (percent * 100);
                mDeckListAdapter.mTextHandledPercent = (String.format(Locale.CHINA, data[2] == 0 ? "已掌握 %.1f" : "已学 %.1f", percent)) + "%";
                // Set estimated time remaining
                int eta = (newCards + revCards) * 10 / 60;
                if ((newCards + revCards) % 60 != 0) {
                    eta++;
                }
                if (eta != -1) {
                    mDeckListAdapter.mTextETA = "" + eta;
                } else {
                    mDeckListAdapter.mTextETA = "-";
                }
                mDeckListAdapter.notifyDataSetChangedAll();
                // Rebuild the options menu
                configureToolbar();
            }
            updateDeckList();
            // If in fragmented mode, refresh the deck list
            if (mFragmented && refreshDecklist) {
                mListener.onRequireDeckListUpdate();
            }
        }
    };
}
Also used : Deck(com.ichi2.libanki.Deck) TaskData(com.ichi2.async.TaskData) TaskListener(com.ichi2.async.TaskListener)

Example 5 with START

use of com.ichi2.anim.ActivityTransitionAnimation.Direction.START in project AnkiChinaAndroid by ankichinateam.

the class UIUtils method saveCollectionInBackground.

public static void saveCollectionInBackground(boolean syncIgnoresDatabaseModification) {
    if (CollectionHelper.getInstance().colIsOpen()) {
        TaskListener listener = new TaskListener() {

            @Override
            public void onPreExecute() {
                Timber.d("saveCollectionInBackground: start");
            }

            @Override
            public void onPostExecute(TaskData result) {
                Timber.d("saveCollectionInBackground: finished");
            }
        };
        CollectionTask.launchCollectionTask(SAVE_COLLECTION, listener, new TaskData(syncIgnoresDatabaseModification));
    }
}
Also used : TaskListener(com.ichi2.async.TaskListener) TaskData(com.ichi2.async.TaskData)

Aggregations

Test (org.junit.Test)23 Intent (android.content.Intent)21 JSONObject (com.ichi2.utils.JSONObject)17 Model (com.ichi2.libanki.Model)14 View (android.view.View)13 ArrayList (java.util.ArrayList)13 Bundle (android.os.Bundle)12 Collection (com.ichi2.libanki.Collection)11 Note (com.ichi2.libanki.Note)9 File (java.io.File)9 JSONArray (com.ichi2.utils.JSONArray)8 SharedPreferences (android.content.SharedPreferences)7 TextView (android.widget.TextView)7 EditText (android.widget.EditText)6 Deck (com.ichi2.libanki.Deck)6 Dialog (android.app.Dialog)5 NonNull (androidx.annotation.NonNull)5 MaterialDialog (com.afollestad.materialdialogs.MaterialDialog)5 RobolectricTest (com.ichi2.anki.RobolectricTest)5 TaskData (com.ichi2.async.TaskData)5