use of com.ichi2.libanki.Models in project Anki-Android by Ramblurr.
the class NoteService method updateJsonNoteFromMultimediaNote.
/**
* Updates the JsonNote field values from MultimediaEditableNote When both notes are using the same Model, it updaes
* the destination field values with source values. If models are different it throws an Exception
*
* @param mNoteSrc
* @param mEditorNoteDst
*/
public static void updateJsonNoteFromMultimediaNote(final IMultimediaEditableNote noteSrc, final Note editorNoteDst) {
if (noteSrc instanceof MultimediaEditableNote) {
MultimediaEditableNote mmNote = (MultimediaEditableNote) noteSrc;
if (mmNote.getModelId() != editorNoteDst.getMid()) {
throw new RuntimeException("Source and Destination Note ID do not match.");
}
int totalFields = mmNote.getNumberOfFields();
for (int i = 0; i < totalFields; i++) {
editorNoteDst.values()[i] = mmNote.getField(i).getFormattedValue();
}
}
}
use of com.ichi2.libanki.Models in project Anki-Android by Ramblurr.
the class MultimediaCardEditorActivity method showModelSelectDialog.
private Dialog showModelSelectDialog() {
StyledDialog dialog = null;
StyledDialog.Builder builder = new StyledDialog.Builder(this);
ArrayList<CharSequence> dialogItems = new ArrayList<CharSequence>();
// Use this array to know which ID is associated with each
// Item(name)
final ArrayList<Long> dialogIds = new ArrayList<Long>();
ArrayList<JSONObject> models = mCol.getModels().all();
Collections.sort(models, new JSONNameComparator());
builder.setTitle(R.string.note_type);
for (JSONObject m : models) {
try {
dialogItems.add(m.getString("name"));
dialogIds.add(m.getLong("id"));
} catch (JSONException e) {
Log.e("Multimedia Editor", e.getMessage());
}
}
// Convert to Array
String[] items2 = new String[dialogItems.size()];
dialogItems.toArray(items2);
builder.setItems(items2, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int item) {
long oldModelId;
try {
oldModelId = mCol.getModels().current().getLong("id");
} catch (JSONException e) {
Log.e("Multimedia Editor", e.getMessage());
return;
}
long newId = dialogIds.get(item);
if (oldModelId != newId) {
changeCurrentModel(newId);
createEditorUI(mNote);
}
}
});
dialog = builder.create();
return dialog;
}
use of com.ichi2.libanki.Models in project Anki-Android by Ramblurr.
the class CardEditor method onCreateDialog.
@Override
protected Dialog onCreateDialog(int id) {
StyledDialog dialog = null;
Resources res = getResources();
StyledDialog.Builder builder = new StyledDialog.Builder(this);
switch(id) {
case DIALOG_TAGS_SELECT:
builder.setTitle(R.string.card_details_tags);
builder.setPositiveButton(res.getString(R.string.select), new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (mAddNote) {
try {
JSONArray ja = new JSONArray();
for (String t : selectedTags) {
ja.put(t);
}
mCol.getModels().current().put("tags", ja);
mCol.getModels().setChanged();
} catch (JSONException e) {
throw new RuntimeException(e);
}
mEditorNote.setTags(selectedTags);
}
mCurrentTags = selectedTags;
updateTags();
}
});
builder.setNegativeButton(res.getString(R.string.cancel), null);
mNewTagEditText = (EditText) new EditText(this);
mNewTagEditText.setHint(R.string.add_new_tag);
InputFilter filter = new InputFilter() {
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
for (int i = start; i < end; i++) {
if (source.charAt(i) == ' ' || source.charAt(i) == ',') {
return "";
}
}
return null;
}
};
mNewTagEditText.setFilters(new InputFilter[] { filter });
ImageView mAddTextButton = new ImageView(this);
mAddTextButton.setImageResource(R.drawable.ic_addtag);
mAddTextButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String tag = mNewTagEditText.getText().toString();
if (tag.length() != 0) {
if (mEditorNote.hasTag(tag)) {
mNewTagEditText.setText("");
return;
}
selectedTags.add(tag);
actualizeTagDialog(mTagsDialog);
mNewTagEditText.setText("");
}
}
});
FrameLayout frame = new FrameLayout(this);
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, Gravity.RIGHT | Gravity.CENTER_VERTICAL);
params.rightMargin = 10;
mAddTextButton.setLayoutParams(params);
frame.addView(mNewTagEditText);
frame.addView(mAddTextButton);
builder.setView(frame, false, true);
dialog = builder.create();
mTagsDialog = dialog;
break;
case DIALOG_DECK_SELECT:
ArrayList<CharSequence> dialogDeckItems = new ArrayList<CharSequence>();
// Use this array to know which ID is associated with each
// Item(name)
final ArrayList<Long> dialogDeckIds = new ArrayList<Long>();
ArrayList<JSONObject> decks = mCol.getDecks().all();
Collections.sort(decks, new JSONNameComparator());
builder.setTitle(R.string.deck);
for (JSONObject d : decks) {
try {
if (d.getInt("dyn") == 0) {
dialogDeckItems.add(d.getString("name"));
dialogDeckIds.add(d.getLong("id"));
}
} catch (JSONException e) {
throw new RuntimeException(e);
}
}
// Convert to Array
String[] items = new String[dialogDeckItems.size()];
dialogDeckItems.toArray(items);
builder.setItems(items, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int item) {
long newId = dialogDeckIds.get(item);
if (mCurrentDid != newId) {
if (mAddNote) {
try {
// TODO: mEditorNote.setDid(newId);
mEditorNote.model().put("did", newId);
mCol.getModels().setChanged();
} catch (JSONException e) {
throw new RuntimeException(e);
}
}
mCurrentDid = newId;
updateDeck();
}
}
});
dialog = builder.create();
mDeckSelectDialog = dialog;
break;
case DIALOG_MODEL_SELECT:
ArrayList<CharSequence> dialogItems = new ArrayList<CharSequence>();
// Use this array to know which ID is associated with each
// Item(name)
final ArrayList<Long> dialogIds = new ArrayList<Long>();
ArrayList<JSONObject> models = mCol.getModels().all();
Collections.sort(models, new JSONNameComparator());
builder.setTitle(R.string.note_type);
for (JSONObject m : models) {
try {
dialogItems.add(m.getString("name"));
dialogIds.add(m.getLong("id"));
} catch (JSONException e) {
throw new RuntimeException(e);
}
}
// Convert to Array
String[] items2 = new String[dialogItems.size()];
dialogItems.toArray(items2);
builder.setItems(items2, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int item) {
long oldModelId;
try {
oldModelId = mCol.getModels().current().getLong("id");
} catch (JSONException e) {
throw new RuntimeException(e);
}
long newId = dialogIds.get(item);
if (oldModelId != newId) {
mCol.getModels().setCurrent(mCol.getModels().get(newId));
JSONObject cdeck = mCol.getDecks().current();
try {
cdeck.put("mid", newId);
} catch (JSONException e) {
throw new RuntimeException(e);
}
mCol.getDecks().save(cdeck);
int size = mEditFields.size();
String[] oldValues = new String[size];
for (int i = 0; i < size; i++) {
oldValues[i] = mEditFields.get(i).getText().toString();
}
setNote();
resetEditFields(oldValues);
mTimerHandler.removeCallbacks(checkDuplicatesRunnable);
duplicateCheck(false);
}
}
});
dialog = builder.create();
break;
case DIALOG_RESET_CARD:
builder.setTitle(res.getString(R.string.reset_card_dialog_title));
builder.setMessage(res.getString(R.string.reset_card_dialog_message));
builder.setPositiveButton(res.getString(R.string.yes), new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// for (long cardId :
// mDeck.getCardsFromFactId(mEditorNote.getId())) {
// mDeck.cardFromId(cardId).resetCard();
// }
// mDeck.reset();
// setResult(Reviewer.RESULT_EDIT_CARD_RESET);
// mCardReset = true;
// Themes.showThemedToast(CardEditor.this,
// getResources().getString(
// R.string.reset_card_dialog_confirmation), true);
}
});
builder.setNegativeButton(res.getString(R.string.no), null);
builder.setCancelable(true);
dialog = builder.create();
break;
case DIALOG_INTENT_INFORMATION:
dialog = createDialogIntentInformation(builder, res);
}
return dialog;
}
use of com.ichi2.libanki.Models in project AnkiChinaAndroid by ankichinateam.
the class NoteEditor method onCollectionLoaded.
// Finish initializing the activity after the collection has been correctly loaded
@Override
protected void onCollectionLoaded(Collection col) {
super.onCollectionLoaded(col);
Intent intent = getIntent();
Timber.d("NoteEditor() onCollectionLoaded: caller: %d", mCaller);
registerExternalStorageListener();
View mainView = findViewById(android.R.id.content);
mToolbar = findViewById(R.id.editor_toolbar);
mToolbar.setFormatListener(formatter -> {
View currentFocus = getCurrentFocus();
if (!(currentFocus instanceof FieldEditText)) {
return;
}
modifyCurrentSelection(formatter, (FieldEditText) currentFocus);
});
enableToolbar(mainView);
mFieldsLayoutContainer = findViewById(R.id.CardEditorEditFieldsLayout);
mTagsButton = findViewById(R.id.CardEditorTagText);
mCardsButton = findViewById(R.id.CardEditorCardsText);
mCardsButton.setOnClickListener(v -> {
Timber.i("NoteEditor:: Cards button pressed. Opening template editor");
showCardTemplateEditor();
});
mAedictIntent = false;
mCurrentEditedCard = null;
switch(mCaller) {
case CALLER_NOCALLER:
Timber.e("no caller could be identified, closing");
finishWithoutAnimation();
return;
case CALLER_REVIEWER:
mCurrentEditedCard = AbstractFlashcardViewer.getEditorCard();
if (mCurrentEditedCard == null) {
finishWithoutAnimation();
return;
}
mEditorNote = mCurrentEditedCard.note();
mAddNote = false;
break;
case CALLER_STUDYOPTIONS:
case CALLER_DECKPICKER:
case CALLER_REVIEWER_ADD:
case CALLER_CARDBROWSER_ADD:
case CALLER_CARDEDITOR:
mAddNote = true;
break;
case CALLER_CARDBROWSER_EDIT:
mCurrentEditedCard = CardBrowser.sCardBrowserCard;
if (mCurrentEditedCard == null) {
finishWithoutAnimation();
return;
}
mEditorNote = mCurrentEditedCard.note();
mAddNote = false;
break;
case CALLER_CARDEDITOR_INTENT_ADD:
{
fetchIntentInformation(intent);
if (mSourceText == null) {
finishWithoutAnimation();
return;
}
if ("Aedict Notepad".equals(mSourceText[0]) && addFromAedict(mSourceText[1])) {
finishWithoutAnimation();
return;
}
mAddNote = true;
break;
}
default:
break;
}
// Note type Selector
mNoteTypeSpinner = findViewById(R.id.note_type_spinner);
ArrayList<Model> models = getCol().getModels().all();
Collections.sort(models, NamedJSONComparator.instance);
final ArrayList<String> modelNames = new ArrayList<>(models.size());
mAllModelIds = new ArrayList<>(models.size());
for (JSONObject m : models) {
modelNames.add(m.getString("name"));
mAllModelIds.add(m.getLong("id"));
}
ArrayAdapter<String> noteTypeAdapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item, modelNames);
mNoteTypeSpinner.setAdapter(noteTypeAdapter);
noteTypeAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
// Deck Selector
TextView deckTextView = findViewById(R.id.CardEditorDeckText);
// If edit mode and more than one card template distinguish between "Deck" and "Card deck"
if (!mAddNote && mEditorNote.model().getJSONArray("tmpls").length() > 1) {
deckTextView.setText(R.string.CardEditorCardDeck);
}
mNoteDeckSpinner = findViewById(R.id.note_deck_spinner);
ArrayList<Deck> decks = getCol().getDecks().all();
Collections.sort(decks, DeckComparator.instance);
final ArrayList<String> deckNames = new ArrayList<>(decks.size());
mAllDeckIds = new ArrayList<>(decks.size());
for (Deck d : decks) {
// add current deck and all other non-filtered decks to deck list
long thisDid = d.getLong("id");
if (d.getInt("dyn") == 0 || (!mAddNote && mCurrentEditedCard != null && mCurrentEditedCard.getDid() == thisDid)) {
deckNames.add(d.getString("name"));
mAllDeckIds.add(thisDid);
}
}
ArrayAdapter<String> noteDeckAdapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item, deckNames);
mNoteDeckSpinner.setAdapter(noteDeckAdapter);
noteDeckAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
mNoteDeckSpinner.setOnItemSelectedListener(new OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
// Timber.i("NoteEditor:: onItemSelected() fired on mNoteDeckSpinner with pos = %d", pos);
mCurrentDid = mAllDeckIds.get(pos);
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
// Do Nothing
}
});
mCurrentDid = intent.getLongExtra(EXTRA_DID, mCurrentDid);
setDid(mEditorNote);
setNote(mEditorNote, FieldChangeType.onActivityCreation(shouldReplaceNewlines()));
if (mAddNote) {
mNoteTypeSpinner.setOnItemSelectedListener(new SetNoteTypeListener());
setTitle(R.string.menu_add_note);
// set information transferred by intent
String contents = null;
String[] tags = intent.getStringArrayExtra(EXTRA_TAGS);
if (mSourceText != null) {
if (mAedictIntent && (mEditFields.size() == 3) && mSourceText[1].contains("[")) {
contents = mSourceText[1].replaceFirst("\\[", "\u001f" + mSourceText[0] + "\u001f");
contents = contents.substring(0, contents.length() - 1);
} else if (mEditFields.size() > 0) {
mEditFields.get(0).setText(mSourceText[0]);
if (mEditFields.size() > 1) {
mEditFields.get(1).setText(mSourceText[1]);
}
}
} else {
contents = intent.getStringExtra(EXTRA_CONTENTS);
}
if (contents != null) {
setEditFieldTexts(contents);
}
if (tags != null) {
setTags(tags);
}
} else {
mNoteTypeSpinner.setOnItemSelectedListener(new EditNoteTypeListener());
setTitle(R.string.cardeditor_title_edit_card);
}
findViewById(R.id.CardEditorTagButton).setOnClickListener(v -> {
Timber.i("NoteEditor:: Tags button pressed... opening tags editor");
showTagsDialog();
});
if (!mAddNote && mCurrentEditedCard != null) {
Timber.i("onCollectionLoaded() Edit note activity successfully started with card id %d", mCurrentEditedCard.getId());
}
if (mAddNote) {
Timber.i("onCollectionLoaded() Edit note activity successfully started in add card mode with node id %d", mEditorNote.getId());
}
// don't open keyboard if not adding note
if (!mAddNote) {
this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
}
// set focus to FieldEditText 'first' on startup like Anki desktop
if (mEditFields != null && !mEditFields.isEmpty()) {
mEditFields.getFirst().requestFocus();
}
}
use of com.ichi2.libanki.Models 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();
}
}
Aggregations