Search in sources :

Example 31 with ANSWER

use of com.ichi2.anki.CardBrowser.Column.ANSWER in project AnkiChinaAndroid by ankichinateam.

the class OverView method loadDataBuilder.

public void loadDataBuilder(OverviewStatsBuilder builder) {
    Timber.d("loadDataBuilder");
    Resources res = getResources();
    findTextViewById(R.id.tv_today).setText(res.getString(R.string.stats_today));
    final int minutes = (int) Math.round(builder.mTodayStats[THETIME_INDEX] / 60.0);
    final String span = res.getQuantityString(R.plurals.time_span_minutes, minutes, minutes);
    findTextViewById(R.id.tv_today_minute).setText(res.getQuantityString(R.plurals.stats_today_cards, builder.mTodayStats[CARDS_INDEX], builder.mTodayStats[CARDS_INDEX], span));
    findTextViewById(R.id.tv_today_repeat).setText(res.getString(R.string.stats_today_again_count, builder.mTodayStats[FAILED_INDEX]));
    if (builder.mTodayStats[CARDS_INDEX] > 0) {
        findTextViewById(R.id.tv_today_correct_rate).setVisibility(VISIBLE);
        findTextViewById(R.id.tv_today_correct_rate).setText(res.getString(R.string.stats_today_correct_count, builder.mTodayStats[CARDS_INDEX] - builder.mTodayStats[FAILED_INDEX], builder.mTodayStats[CARDS_INDEX], (((1 - builder.mTodayStats[FAILED_INDEX] / (float) (builder.mTodayStats[CARDS_INDEX])) * 100.0))));
    } else {
        findTextViewById(R.id.tv_today_correct_rate).setVisibility(GONE);
    }
    findTextViewById(R.id.tv_today_study).setText(res.getString(R.string.stats_today_type_breakdown, builder.mTodayStats[LRN_INDEX], builder.mTodayStats[REV_INDEX], builder.mTodayStats[RELRN_INDEX], builder.mTodayStats[FILT_INDEX]));
    if (builder.mTodayStats[MCNT_INDEX] != 0) {
        findTextViewById(R.id.tv_today_hint).setText(res.getString(R.string.stats_today_mature_cards, builder.mTodayStats[MSUM_INDEX], builder.mTodayStats[MCNT_INDEX], (builder.mTodayStats[MSUM_INDEX] / (float) (builder.mTodayStats[MCNT_INDEX]) * 100.0)));
    } else {
        findTextViewById(R.id.tv_today_hint).setText(res.getString(R.string.stats_today_no_mature_cards));
    }
    findTextViewById(R.id.description).setText(res.getString(builder.mType.descriptionId));
    OverviewStatsBuilder.OverviewStats oStats = builder.mOverViewStats;
    // FORECAST
    findTextViewById(R.id.tv_predict).setText(res.getString(R.string.stats_forecast).toUpperCase());
    findTextViewById(R.id.tv_predict_all_content).setText(res.getString(R.string.stats_overview_forecast_total, oStats.forecastTotalReviews));
    findTextViewById(R.id.tv_predict_avg_content).setText(res.getString(R.string.stats_overview_forecast_average, oStats.forecastAverageReviews));
    findTextViewById(R.id.tv_predict_deadline_content).setText(res.getString(R.string.stats_overview_forecast_due_tomorrow, oStats.forecastDueTomorrow));
    // REVIEW COUNT
    findTextViewById(R.id.tv_review).setText(res.getString(R.string.stats_review_count).toUpperCase());
    findTextViewById(R.id.tv_review_day_content).setText(oStats.daysStudied + "/" + oStats.allDays);
    findTextViewById(R.id.tv_review_day_percent).setText("(" + (int) ((float) oStats.daysStudied / (float) oStats.allDays * 100) + "%)");
    findTextViewById(R.id.tv_review_all_content).setText(res.getString(R.string.stats_overview_total_reviews, oStats.totalReviews));
    findTextViewById(R.id.tv_review_avg_content).setText(res.getString(R.string.stats_overview_reviews_per_day_studydays, oStats.reviewsPerDayOnStudyDays));
    boolean allDaysStudied = oStats.daysStudied == oStats.allDays;
    if (!allDaysStudied) {
        findTextViewById(R.id.tv_review_hint).setText(res.getString(R.string.stats_overview_reviews_per_day_all, oStats.reviewsPerDayOnAll));
        findTextViewById(R.id.tv_review_hint).setVisibility(VISIBLE);
    } else {
        findTextViewById(R.id.tv_review_hint).setVisibility(GONE);
    }
    // REVIEW TIME
    findTextViewById(R.id.tv_review_time).setText(res.getString(R.string.stats_review_time).toUpperCase());
    findTextViewById(R.id.tv_review_time_count_content).setText(oStats.daysStudied + "/" + oStats.allDays);
    findTextViewById(R.id.tv_review_time_count_percent).setText("(" + (int) ((float) oStats.daysStudied / (float) oStats.allDays * 100) + "%)");
    findTextViewById(R.id.tv_review_time_all_content).setText(res.getString(R.string.stats_overview_total_time_in_period, Math.round(oStats.totalTime)));
    findTextViewById(R.id.tv_review_time_avg_content).setText(res.getString(R.string.stats_overview_time_per_day_studydays, oStats.timePerDayOnStudyDays));
    double cardsPerMinute = oStats.totalTime == 0 ? 0 : ((double) oStats.totalReviews) / oStats.totalTime;
    double averageAnswerTime = oStats.totalReviews == 0 ? 0 : (oStats.totalTime * 60) / ((double) oStats.totalReviews);
    if (!allDaysStudied) {
        findTextViewById(R.id.tv_review_time_hint).setText(res.getString(R.string.stats_overview_time_per_day_all, oStats.timePerDayOnAll) + "," + res.getString(R.string.stats_overview_average_answer_time, averageAnswerTime, cardsPerMinute));
    } else {
        findTextViewById(R.id.tv_review_time_hint).setText(res.getString(R.string.stats_overview_average_answer_time, averageAnswerTime, cardsPerMinute));
    }
    // ADDED
    findTextViewById(R.id.tv_add).setText(res.getString(R.string.stats_added).toUpperCase());
    findTextViewById(R.id.tv_add_all_content).setText(res.getString(R.string.stats_overview_total_new_cards, oStats.totalNewCards));
    findTextViewById(R.id.tv_add_avg_content).setText(res.getString(R.string.stats_overview_new_cards_per_day, oStats.newCardsPerDay));
    // INTERVALS
    findTextViewById(R.id.tv_distance).setText(res.getString(R.string.stats_review_intervals).toUpperCase());
    findTextViewById(R.id.tv_distance_avg).setText(res.getString(R.string.stats_overview_average_interval));
    findTextViewById(R.id.tv_distance_avg_content).setText(Utils.roundedTimeSpan(getContext(), (int) Math.round(oStats.averageInterval * Stats.SECONDS_PER_DAY)));
    findTextViewById(R.id.tv_distance_max).setText(res.getString(R.string.stats_overview_longest_interval));
    findTextViewById(R.id.tv_distance_all_content).setText(Utils.roundedTimeSpan(getContext(), (int) Math.round(oStats.longestInterval * Stats.SECONDS_PER_DAY)));
    // ANSWER BUTTONS
    findTextViewById(R.id.tv_answer_button).setText(res.getString(R.string.stats_answer_buttons).toUpperCase());
    findTextViewById(R.id.tv_answer_study_content).setText(res.getString(R.string.stats_overview_answer_buttons_learn, oStats.newCardsOverview.getPercentage()));
    findTextViewById(R.id.tv_answer_study_percent).setText("(" + oStats.newCardsOverview.correct + "/" + oStats.newCardsOverview.total + ")");
    findTextViewById(R.id.tv_answer_not_familiar_content).setText(res.getString(R.string.stats_overview_answer_buttons_young, oStats.youngCardsOverview.getPercentage()));
    findTextViewById(R.id.tv_answer_not_familiar_percent).setText("(" + oStats.youngCardsOverview.correct + "/" + oStats.youngCardsOverview.total + ")");
    findTextViewById(R.id.tv_answer_familiar_content).setText(res.getString(R.string.stats_overview_answer_buttons_mature, oStats.matureCardsOverview.getPercentage()));
    findTextViewById(R.id.tv_answer_familiar_percent).setText("(" + oStats.matureCardsOverview.correct + "/" + oStats.matureCardsOverview.total + ")");
    // CARD TYPES
    findTextViewById(R.id.tv_note_type).setText(res.getString(R.string.stats_cards_types).toUpperCase());
    findTextViewById(R.id.tv_note_type_all_card).setText(R.string.stats_overview_card_types_total_cards);
    findTextViewById(R.id.tv_note_type_all_card_content).setText("" + oStats.totalCards);
    findTextViewById(R.id.tv_note_type_all).setText(R.string.stats_overview_card_types_total_notes);
    findTextViewById(R.id.tv_note_type_all_content).setText("" + oStats.totalNotes);
    findTextViewById(R.id.tv_note_low_level).setText(R.string.stats_overview_card_types_lowest_ease);
    findTextViewById(R.id.tv_note_low_level_content).setText(oStats.lowestEase + "%");
    findTextViewById(R.id.tv_note_avg_level).setText(R.string.stats_overview_card_types_average_ease);
    findTextViewById(R.id.tv_note_avg_level_content).setText(oStats.averageEase + "%");
    findTextViewById(R.id.tv_note_high_level).setText(R.string.stats_overview_card_types_highest_ease);
    findTextViewById(R.id.tv_note_high_level_content).setText(oStats.highestEase + "%");
}
Also used : OverviewStatsBuilder(com.ichi2.anki.stats.OverviewStatsBuilder) Resources(android.content.res.Resources) SuppressLint(android.annotation.SuppressLint)

Example 32 with ANSWER

use of com.ichi2.anki.CardBrowser.Column.ANSWER in project AnkiChinaAndroid by ankichinateam.

the class CardContentProvider method insert.

@Override
public Uri insert(Uri uri, ContentValues values) {
    if (!hasReadWritePermission() && shouldEnforceQueryOrInsertSecurity()) {
        throwSecurityException("insert", uri);
    }
    Collection col = CollectionHelper.getInstance().getCol(mContext);
    if (col == null) {
        throw new IllegalStateException(COL_NULL_ERROR_MSG);
    }
    col.log(getLogMessage("insert", uri));
    // Find out what data the user is requesting
    int match = sUriMatcher.match(uri);
    switch(match) {
        case NOTES:
            {
                /* Insert new note with specified fields and tags
                 */
                Long modelId = values.getAsLong(FlashCardsContract.Note.MID);
                String flds = values.getAsString(FlashCardsContract.Note.FLDS);
                String tags = values.getAsString(FlashCardsContract.Note.TAGS);
                // Create empty note
                com.ichi2.libanki.Note newNote = new com.ichi2.libanki.Note(col, col.getModels().get(modelId));
                // Set fields
                String[] fldsArray = Utils.splitFields(flds);
                // Check that correct number of flds specified
                if (fldsArray.length != newNote.getFields().length) {
                    throw new IllegalArgumentException("Incorrect flds argument : " + flds);
                }
                for (int idx = 0; idx < fldsArray.length; idx++) {
                    newNote.setField(idx, fldsArray[idx]);
                }
                // Set tags
                if (tags != null) {
                    newNote.setTagsFromStr(tags);
                }
                // Add to collection
                col.addNote(newNote);
                col.save();
                return Uri.withAppendedPath(FlashCardsContract.Note.CONTENT_URI, Long.toString(newNote.getId()));
            }
        case NOTES_ID:
            // Note ID is generated automatically by libanki
            throw new IllegalArgumentException("Not possible to insert note with specific ID");
        case NOTES_ID_CARDS:
            // Cards are generated automatically by libanki
            throw new IllegalArgumentException("Not possible to insert cards directly (only through NOTES)");
        case NOTES_ID_CARDS_ORD:
            // Cards are generated automatically by libanki
            throw new IllegalArgumentException("Not possible to insert cards directly (only through NOTES)");
        case MODELS:
            // Get input arguments
            String modelName = values.getAsString(FlashCardsContract.Model.NAME);
            String css = values.getAsString(FlashCardsContract.Model.CSS);
            Long did = values.getAsLong(FlashCardsContract.Model.DECK_ID);
            String fieldNames = values.getAsString(FlashCardsContract.Model.FIELD_NAMES);
            Integer numCards = values.getAsInteger(FlashCardsContract.Model.NUM_CARDS);
            Integer sortf = values.getAsInteger(FlashCardsContract.Model.SORT_FIELD_INDEX);
            Integer type = values.getAsInteger(FlashCardsContract.Model.TYPE);
            String latexPost = values.getAsString(FlashCardsContract.Model.LATEX_POST);
            String latexPre = values.getAsString(FlashCardsContract.Model.LATEX_PRE);
            // Throw exception if required fields empty
            if (modelName == null || fieldNames == null || numCards == null) {
                throw new IllegalArgumentException("Model name, field_names, and num_cards can't be empty");
            }
            if (did != null && col.getDecks().isDyn(did)) {
                throw new IllegalArgumentException("Cannot set a filtered deck as default deck for a model");
            }
            // Create a new model
            Models mm = col.getModels();
            Model newModel = mm.newModel(modelName);
            try {
                // Add the fields
                String[] allFields = Utils.splitFields(fieldNames);
                for (String f : allFields) {
                    mm.addFieldInNewModel(newModel, mm.newField(f));
                }
                // Add some empty card templates
                for (int idx = 0; idx < numCards; idx++) {
                    JSONObject t = mm.newTemplate("Card " + (idx + 1));
                    t.put("qfmt", String.format("{{%s}}", allFields[0]));
                    String answerField = allFields[0];
                    if (allFields.length > 1) {
                        answerField = allFields[1];
                    }
                    t.put("afmt", String.format("{{FrontSide}}\\n\\n<hr id=answer>\\n\\n{{%s}}", answerField));
                    mm.addTemplateInNewModel(newModel, t);
                }
                // Add the CSS if specified
                if (css != null) {
                    newModel.put("css", css);
                }
                // Add the did if specified
                if (did != null) {
                    newModel.put("did", did);
                }
                if (sortf != null && sortf < allFields.length) {
                    newModel.put("sortf", sortf);
                }
                if (type != null) {
                    newModel.put("type", type);
                }
                if (latexPost != null) {
                    newModel.put("latexPost", latexPost);
                }
                if (latexPre != null) {
                    newModel.put("latexPre", latexPre);
                }
                // Add the model to collection (from this point on edits will require a full-sync)
                mm.add(newModel);
                col.save();
                // Get the mid and return a URI
                String mid = Long.toString(newModel.getLong("id"));
                return Uri.withAppendedPath(FlashCardsContract.Model.CONTENT_URI, mid);
            } catch (JSONException e) {
                Timber.e(e, "Could not set a field of new model %s", modelName);
                return null;
            }
        case MODELS_ID:
            // Model ID is generated automatically by libanki
            throw new IllegalArgumentException("Not possible to insert model with specific ID");
        case MODELS_ID_TEMPLATES:
            {
                Models models = col.getModels();
                Long mid = getModelIdFromUri(uri, col);
                Model existingModel = models.get(mid);
                if (existingModel == null) {
                    throw new IllegalArgumentException("model missing: " + mid);
                }
                String name = values.getAsString(CardTemplate.NAME);
                String qfmt = values.getAsString(CardTemplate.QUESTION_FORMAT);
                String afmt = values.getAsString(CardTemplate.ANSWER_FORMAT);
                String bqfmt = values.getAsString(CardTemplate.BROWSER_QUESTION_FORMAT);
                String bafmt = values.getAsString(CardTemplate.BROWSER_ANSWER_FORMAT);
                try {
                    JSONObject t = models.newTemplate(name);
                    t.put("qfmt", qfmt);
                    t.put("afmt", afmt);
                    t.put("bqfmt", bqfmt);
                    t.put("bafmt", bafmt);
                    models.addTemplate(existingModel, t);
                    models.save(existingModel);
                    col.save();
                    return ContentUris.withAppendedId(uri, t.getInt("ord"));
                } catch (ConfirmModSchemaException e) {
                    throw new IllegalArgumentException("Unable to add template without user requesting/accepting full-sync", e);
                } catch (JSONException e) {
                    throw new IllegalArgumentException("Unable to get ord from new template", e);
                }
            }
        case MODELS_ID_TEMPLATES_ID:
            throw new IllegalArgumentException("Not possible to insert template with specific ORD");
        case MODELS_ID_FIELDS:
            {
                Models models = col.getModels();
                Long mid = getModelIdFromUri(uri, col);
                Model existingModel = models.get(mid);
                if (existingModel == null) {
                    throw new IllegalArgumentException("model missing: " + mid);
                }
                String name = values.getAsString(FlashCardsContract.Model.FIELD_NAME);
                if (name == null) {
                    throw new IllegalArgumentException("field name missing for model: " + mid);
                }
                JSONObject field = models.newField(name);
                try {
                    models.addField(existingModel, field);
                    col.save();
                    JSONArray flds = existingModel.getJSONArray("flds");
                    return ContentUris.withAppendedId(uri, flds.length() - 1);
                } catch (ConfirmModSchemaException e) {
                    throw new IllegalArgumentException("Unable to insert field: " + name, e);
                } catch (JSONException e) {
                    throw new IllegalArgumentException("Unable to get newly created field: " + name, e);
                }
            }
        case SCHEDULE:
            // Doesn't make sense to insert an object into the schedule table
            throw new IllegalArgumentException("Not possible to perform insert operation on schedule");
        case DECKS:
            // Insert new deck with specified name
            String deckName = values.getAsString(FlashCardsContract.Deck.DECK_NAME);
            did = col.getDecks().id(deckName, false);
            if (did != null) {
                throw new IllegalArgumentException("Deck name already exists: " + deckName);
            }
            if (!Decks.isValidDeckName(deckName)) {
                throw new IllegalArgumentException("Invalid deck name '" + deckName + "'");
            }
            did = col.getDecks().id(deckName, true);
            Deck deck = col.getDecks().get(did);
            if (deck != null) {
                try {
                    String deckDesc = values.getAsString(FlashCardsContract.Deck.DECK_DESC);
                    if (deckDesc != null) {
                        deck.put("desc", deckDesc);
                    }
                } catch (JSONException e) {
                    Timber.e(e, "Could not set a field of new deck %s", deckName);
                    return null;
                }
            }
            col.getDecks().flush();
            return Uri.withAppendedPath(FlashCardsContract.Deck.CONTENT_ALL_URI, Long.toString(did));
        case DECK_SELECTED:
            // Can't have more than one selected deck
            throw new IllegalArgumentException("Selected deck can only be queried and updated");
        case DECKS_ID:
            // Deck ID is generated automatically by libanki
            throw new IllegalArgumentException("Not possible to insert deck with specific ID");
        default:
            // Unknown URI type
            throw new IllegalArgumentException("uri " + uri + " is not supported");
    }
}
Also used : Note(com.ichi2.libanki.Note) JSONArray(com.ichi2.utils.JSONArray) JSONException(com.ichi2.utils.JSONException) Deck(com.ichi2.libanki.Deck) JSONObject(com.ichi2.utils.JSONObject) Note(com.ichi2.libanki.Note) Model(com.ichi2.libanki.Model) Collection(com.ichi2.libanki.Collection) ConfirmModSchemaException(com.ichi2.anki.exception.ConfirmModSchemaException) Models(com.ichi2.libanki.Models)

Example 33 with ANSWER

use of com.ichi2.anki.CardBrowser.Column.ANSWER in project AnkiChinaAndroid by ankichinateam.

the class CardTemplatePreviewerTest method testPreviewNormal.

@Test
public void testPreviewNormal() throws Exception {
    // Make sure we test previewing a new card template
    String modelName = "Basic (and reversed card)";
    Model collectionBasicModelOriginal = getCurrentDatabaseModelCopy(modelName);
    Card testCard1 = getSavedCard(collectionBasicModelOriginal, 0);
    Card testCard2 = getSavedCard(collectionBasicModelOriginal, 1);
    Intent intent = new Intent(Intent.ACTION_VIEW);
    intent.putExtra("cardList", new long[] { testCard1.getId(), testCard2.getId() });
    intent.putExtra("index", 0);
    ActivityController<TestCardTemplatePreviewer> previewerController = Robolectric.buildActivity(TestCardTemplatePreviewer.class, intent).create().start().resume().visible();
    saveControllerForCleanup(previewerController);
    // Take it through a destroy/re-create lifecycle in order to test instance state persistence
    Bundle outBundle = new Bundle();
    previewerController.saveInstanceState(outBundle);
    previewerController.pause().stop().destroy();
    previewerController = Robolectric.buildActivity(TestCardTemplatePreviewer.class).create(outBundle).start().resume().visible();
    saveControllerForCleanup((previewerController));
    TestCardTemplatePreviewer testCardTemplatePreviewer = (TestCardTemplatePreviewer) previewerController.get();
    // Make sure we can click
    Assert.assertFalse("Showing the answer already?", testCardTemplatePreviewer.getShowingAnswer());
    testCardTemplatePreviewer.disableDoubleClickPrevention();
    View showAnswerButton = testCardTemplatePreviewer.findViewById(R.id.preview_buttons_layout);
    showAnswerButton.performClick();
    Assert.assertTrue("Not showing the answer?", testCardTemplatePreviewer.getShowingAnswer());
}
Also used : Bundle(android.os.Bundle) Model(com.ichi2.libanki.Model) Intent(android.content.Intent) View(android.view.View) Card(com.ichi2.libanki.Card) Test(org.junit.Test)

Example 34 with ANSWER

use of com.ichi2.anki.CardBrowser.Column.ANSWER in project AnkiChinaAndroid by ankichinateam.

the class AbstractFlashcardViewer method updateTypeAnswerInfo.

/**
 * Extract type answer/cloze text and font/size
 */
private void updateTypeAnswerInfo() {
    mTypeCorrect = null;
    mTypeInput = "";
    String q = mCurrentCard.q(false);
    Matcher m = sTypeAnsPat.matcher(q);
    int clozeIdx = 0;
    if (!m.find()) {
        return;
    }
    String fld = m.group(1);
    // if it's a cloze, extract data
    if (fld.startsWith("cloze:", 0)) {
        // get field and cloze position
        clozeIdx = mCurrentCard.getOrd() + 1;
        fld = fld.split(":")[1];
    }
    // loop through fields for a match
    JSONArray flds = mCurrentCard.model().getJSONArray("flds");
    for (int i = 0; i < flds.length(); i++) {
        String name = flds.getJSONObject(i).getString("name");
        if (name.equals(fld)) {
            mTypeCorrect = mCurrentCard.note().getItem(name);
            if (clozeIdx != 0) {
                // narrow to cloze
                mTypeCorrect = contentForCloze(mTypeCorrect, clozeIdx);
            }
            mTypeFont = flds.getJSONObject(i).getString("font");
            mTypeSize = flds.getJSONObject(i).getInt("size");
            break;
        }
    }
    if (mTypeCorrect == null) {
        if (clozeIdx != 0) {
            mTypeWarning = getResources().getString(R.string.empty_card_warning);
        } else {
            mTypeWarning = getResources().getString(R.string.unknown_type_field_warning, fld);
        }
    } else if ("".equals(mTypeCorrect)) {
        mTypeCorrect = null;
    } else {
        mTypeWarning = null;
    }
}
Also used : Matcher(java.util.regex.Matcher) JSONArray(com.ichi2.utils.JSONArray) SuppressLint(android.annotation.SuppressLint)

Example 35 with ANSWER

use of com.ichi2.anki.CardBrowser.Column.ANSWER in project AnkiChinaAndroid by ankichinateam.

the class ImportTest method csvManualLineBreakExample.

@Test
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
public void csvManualLineBreakExample() throws IOException {
    String file = Shared.getTestFilePath(InstrumentationRegistry.getInstrumentation().getTargetContext(), "text-anki-manual-csv-multi-line.txt");
    TextImporter i = new TextImporter(testCol, file);
    i.setAllowHtml(true);
    i.initMapping();
    i.run();
    Note n = testCol.getNote(testCol.getDb().queryLongScalar("select id from notes"));
    assertThat(Arrays.asList(n.getFields()), contains("hello", "this is\na two line answer"));
}
Also used : Note(com.ichi2.libanki.Note) TextImporter(com.ichi2.libanki.importer.TextImporter) Test(org.junit.Test) SdkSuppress(androidx.test.filters.SdkSuppress)

Aggregations

Test (org.junit.Test)29 Collection (com.ichi2.libanki.Collection)20 Note (com.ichi2.libanki.Note)20 Card (com.ichi2.libanki.Card)17 RobolectricTest (com.ichi2.anki.RobolectricTest)16 View (android.view.View)9 Intent (android.content.Intent)8 JSONArray (com.ichi2.utils.JSONArray)8 JSONObject (com.ichi2.utils.JSONObject)8 Model (com.ichi2.libanki.Model)7 Bundle (android.os.Bundle)6 WebView (android.webkit.WebView)6 SuppressLint (android.annotation.SuppressLint)5 SharedPreferences (android.content.SharedPreferences)5 TextView (android.widget.TextView)5 ConfirmModSchemaException (com.ichi2.anki.exception.ConfirmModSchemaException)5 Matcher (java.util.regex.Matcher)5 InputMethodManager (android.view.inputmethod.InputMethodManager)4 Context (android.content.Context)3 Uri (android.net.Uri)3