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 + "%");
}
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");
}
}
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());
}
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;
}
}
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"));
}
Aggregations