use of com.ichi2.anki.Reviewer in project AnkiChinaAndroid by ankichinateam.
the class CardBrowser method onActivityResult.
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// FIXME:
Timber.d("onActivityResult(requestCode=%d, resultCode=%d)", requestCode, resultCode);
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == DeckPicker.RESULT_DB_ERROR) {
closeCardBrowser(DeckPicker.RESULT_DB_ERROR);
}
if (requestCode == EDIT_CARD && resultCode != RESULT_CANCELED) {
Timber.i("CardBrowser:: CardBrowser: Saving card...");
CollectionTask.launchCollectionTask(UPDATE_NOTE, updateCardHandler(), new TaskData(sCardBrowserCard, false));
} else if (requestCode == ADD_NOTE && resultCode == RESULT_OK) {
if (mSearchView != null) {
mSearchTerms = mSearchView.getQuery().toString();
searchCards();
} else {
Timber.w("Note was added from browser and on return mSearchView == null");
}
}
// Previewing can now perform an "edit", so it can pass on a reloadRequired
if (requestCode == PREVIEW_CARDS && data != null && (data.getBooleanExtra("reloadRequired", false) || data.getBooleanExtra("noteChanged", false))) {
searchCards();
if (getReviewerCardId() == mCurrentCardId) {
mReloadRequired = true;
}
}
if (requestCode == EDIT_CARD && data != null && (data.getBooleanExtra("reloadRequired", false) || data.getBooleanExtra("noteChanged", false))) {
// if reloadRequired or noteChanged flag was sent from note editor then reload card list
searchCards();
// in use by reviewer?
if (getReviewerCardId() == mCurrentCardId) {
mReloadRequired = true;
}
}
// maybe the availability of undo changed
invalidateOptionsMenu();
}
use of com.ichi2.anki.Reviewer in project AnkiChinaAndroid by ankichinateam.
the class CustomStudyDialog method buildInputDialog.
/**
* Build an input dialog that is used to get a parameter related to custom study from the user
*
* @param dialogId
* @return
*/
private MaterialDialog buildInputDialog(final int dialogId) {
/*
TODO: Try to change to a standard input dialog (currently the thing holding us back is having the extra
TODO: hint line for the number of cards available, and having the pre-filled text selected by default)
*/
// Input dialogs
Resources res = getActivity().getResources();
// Show input dialog for an individual custom study dialog
View v = getActivity().getLayoutInflater().inflate(R.layout.styled_custom_study_details_dialog, null);
TextView textView1 = (TextView) v.findViewById(R.id.custom_study_details_text1);
TextView textView2 = (TextView) v.findViewById(R.id.custom_study_details_text2);
final EditText mEditText = (EditText) v.findViewById(R.id.custom_study_details_edittext2);
// Set the text
textView1.setText(getText1());
textView2.setText(getText2());
mEditText.setText(getDefaultValue());
// Give EditText focus and show keyboard
mEditText.setSelectAllOnFocus(true);
mEditText.requestFocus();
if (dialogId == CUSTOM_STUDY_NEW || dialogId == CUSTOM_STUDY_REV) {
mEditText.setInputType(EditorInfo.TYPE_CLASS_NUMBER | EditorInfo.TYPE_NUMBER_FLAG_SIGNED);
}
// deck id
final long did = getArguments().getLong("did");
// Whether or not to jump straight to the reviewer
final boolean jumpToReviewer = getArguments().getBoolean("jumpToReviewer");
// Set builder parameters
MaterialDialog.Builder builder = new MaterialDialog.Builder(getActivity()).customView(v, true).positiveText(res.getString(R.string.dialog_ok)).negativeText(res.getString(R.string.dialog_cancel)).onPositive((dialog, which) -> {
Collection col = CollectionHelper.getInstance().getCol(getActivity());
// Get the value selected by user
int n;
try {
n = Integer.parseInt(mEditText.getText().toString());
} catch (Exception ignored) {
// This should never happen because we disable positive button for non-parsable inputs
return;
}
// Set behavior when clicking OK button
switch(dialogId) {
case CUSTOM_STUDY_NEW:
{
AnkiDroidApp.getSharedPrefs(getActivity()).edit().putInt("extendNew", n).commit();
Deck deck = col.getDecks().get(did);
deck.put("extendNew", n);
col.getDecks().save(deck);
col.getSched().extendLimits(n, 0);
onLimitsExtended(jumpToReviewer);
break;
}
case CUSTOM_STUDY_REV:
{
AnkiDroidApp.getSharedPrefs(getActivity()).edit().putInt("extendRev", n).commit();
Deck deck = col.getDecks().get(did);
deck.put("extendRev", n);
col.getDecks().save(deck);
col.getSched().extendLimits(0, n);
onLimitsExtended(jumpToReviewer);
break;
}
case CUSTOM_STUDY_FORGOT:
{
JSONArray ar = new JSONArray();
ar.put(0, 1);
createCustomStudySession(ar, new Object[] { String.format(Locale.US, "rated:%d:1", n), Consts.DYN_MAX_SIZE, Consts.DYN_RANDOM }, false);
break;
}
case CUSTOM_STUDY_AHEAD:
{
createCustomStudySession(new JSONArray(), new Object[] { String.format(Locale.US, "prop:due<=%d", n), Consts.DYN_MAX_SIZE, Consts.DYN_DUE }, true);
break;
}
case CUSTOM_STUDY_RANDOM:
{
createCustomStudySession(new JSONArray(), new Object[] { "", n, Consts.DYN_RANDOM }, true);
break;
}
case CUSTOM_STUDY_PREVIEW:
{
createCustomStudySession(new JSONArray(), new Object[] { "is:new added:" + Integer.toString(n), Consts.DYN_MAX_SIZE, Consts.DYN_OLDEST }, false);
break;
}
default:
break;
}
}).onNegative((dialog, which) -> getAnkiActivity().dismissAllDialogFragments());
final MaterialDialog dialog = builder.build();
mEditText.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void afterTextChanged(Editable editable) {
try {
Integer.parseInt(mEditText.getText().toString());
dialog.getActionButton(DialogAction.POSITIVE).setEnabled(true);
} catch (Exception ignored) {
dialog.getActionButton(DialogAction.POSITIVE).setEnabled(false);
}
}
});
// Show soft keyboard
dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
return dialog;
}
use of com.ichi2.anki.Reviewer in project AnkiChinaAndroid by ankichinateam.
the class SelfStudyActivity method onActivityResult.
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// FIXME:
Timber.d("onActivityResult(requestCode=%d, resultCode=%d)", requestCode, resultCode);
if (data != null) {
Timber.d("onActivityResult data (reloadRequired=%s, noteChanged=%s)", data.getBooleanExtra("reloadRequired", false), data.getBooleanExtra("noteChanged", false));
}
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == DeckPicker.RESULT_DB_ERROR) {
closeCardBrowser(DeckPicker.RESULT_DB_ERROR);
}
if (requestCode == EDIT_CARD && resultCode != RESULT_CANCELED) {
Timber.i("CardBrowser:: CardBrowser: Saving card...");
CollectionTask.launchCollectionTask(UPDATE_NOTE, updateCardHandler(), new TaskData(sCardBrowserCard, false));
} else if (requestCode == ADD_NOTE && resultCode == RESULT_OK) {
if (mSearchView != null) {
mSearchTerms = mSearchView.getQuery().toString();
searchCards();
} else {
Timber.w("Note was added from browser and on return mSearchView == null");
}
}
// }
if (requestCode == PREVIEW_CARDS && data != null && (data.getBooleanExtra("reloadRequired", false) || data.getBooleanExtra("noteChanged", false))) {
searchCards();
if (getReviewerCardId() == mCurrentCardId) {
mReloadRequired = true;
}
}
if (requestCode == EDIT_CARD && data != null && (data.getBooleanExtra("reloadRequired", false) || data.getBooleanExtra("noteChanged", false))) {
// if reloadRequired or noteChanged flag was sent from note editor then reload card list
searchCards();
// in use by reviewer?
if (getReviewerCardId() == mCurrentCardId) {
mReloadRequired = true;
}
}
// maybe the availability of undo changed
invalidateOptionsMenu();
}
use of com.ichi2.anki.Reviewer in project AnkiChinaAndroid by ankichinateam.
the class CollectionTask method doInBackgroundDismissNotes.
private TaskData doInBackgroundDismissNotes(TaskData param) {
Collection col = getCol();
AbstractSched sched = col.getSched();
Object[] data = param.getObjArray();
long[] cardIds = (long[]) data[0];
// query cards
Card[] cards = new Card[cardIds.length];
for (int i = 0; i < cardIds.length; i++) {
cards[i] = col.getCard(cardIds[i]);
}
Collection.DismissType type = (Collection.DismissType) data[1];
try {
col.getDb().getDatabase().beginTransaction();
try {
switch(type) {
case SUSPEND_CARD_MULTI:
{
// collect undo information
long[] cids = new long[cards.length];
boolean[] originalSuspended = new boolean[cards.length];
boolean hasUnsuspended = false;
for (int i = 0; i < cards.length; i++) {
Card card = cards[i];
cids[i] = card.getId();
if (card.getQueue() != Consts.QUEUE_TYPE_SUSPENDED) {
hasUnsuspended = true;
originalSuspended[i] = false;
} else {
originalSuspended[i] = true;
}
}
// otherwise unsuspend all
if (hasUnsuspended) {
sched.suspendCards(cids);
} else {
sched.unsuspendCards(cids);
}
Undoable suspendCardMulti = new UndoSuspendCardMulti(cards, originalSuspended);
// mark undo for all at once
col.markUndo(suspendCardMulti);
// reload cards because they'll be passed back to caller
for (Card c : cards) {
c.load();
}
sched.deferReset();
break;
}
case FLAG:
{
int flag = (Integer) data[2];
col.setUserFlag(flag, cardIds);
for (Card c : cards) {
c.load();
}
break;
}
case MARK_NOTE_MULTI:
{
Set<Note> notes = CardUtils.getNotes(Arrays.asList(cards));
// collect undo information
List<Note> originalMarked = new ArrayList<>();
List<Note> originalUnmarked = new ArrayList<>();
for (Note n : notes) {
if (n.hasTag("marked")) {
originalMarked.add(n);
} else {
originalUnmarked.add(n);
}
}
CardUtils.markAll(new ArrayList<>(notes), !originalUnmarked.isEmpty());
Undoable markNoteMulti = new UndoMarkNoteMulti(originalMarked, originalUnmarked);
// mark undo for all at once
col.markUndo(markNoteMulti);
// reload cards because they'll be passed back to caller
for (Card c : cards) {
c.load();
}
break;
}
case DELETE_NOTE_MULTI:
{
// list of all ids to pass to remNotes method.
// Need Set (-> unique) so we don't pass duplicates to col.remNotes()
Set<Note> notes = CardUtils.getNotes(Arrays.asList(cards));
List<Card> allCards = CardUtils.getAllCards(notes);
// delete note
long[] uniqueNoteIds = new long[notes.size()];
Note[] notesArr = notes.toArray(new Note[notes.size()]);
int count = 0;
for (Note note : notes) {
uniqueNoteIds[count] = note.getId();
count++;
}
Undoable deleteNoteMulti = new UndoDeleteNoteMulti(notesArr, allCards);
col.markUndo(deleteNoteMulti);
col.remNotes(uniqueNoteIds);
sched.deferReset();
// pass back all cards because they can't be retrieved anymore by the caller (since the note is deleted)
publishProgress(new TaskData(allCards.toArray(new Card[allCards.size()])));
break;
}
case CHANGE_DECK_MULTI:
{
long newDid = (long) data[2];
Timber.i("Changing %d cards to deck: '%d'", cards.length, newDid);
Deck deckData = col.getDecks().get(newDid);
if (Decks.isDynamic(deckData)) {
// #5932 - can't change to a dynamic deck. Use "Rebuild"
Timber.w("Attempted to move to dynamic deck. Cancelling task.");
return new TaskData(false);
}
// Confirm that the deck exists (and is not the default)
try {
long actualId = deckData.getLong("id");
if (actualId != newDid) {
Timber.w("Attempted to move to deck %d, but got %d", newDid, actualId);
return new TaskData(false);
}
} catch (Exception e) {
Timber.e(e, "failed to check deck");
return new TaskData(false);
}
long[] changedCardIds = new long[cards.length];
for (int i = 0; i < cards.length; i++) {
changedCardIds[i] = cards[i].getId();
}
col.getSched().remFromDyn(changedCardIds);
long[] originalDids = new long[cards.length];
for (int i = 0; i < cards.length; i++) {
Card card = cards[i];
card.load();
// save original did for undo
originalDids[i] = card.getDid();
// then set the card ID to the new deck
card.setDid(newDid);
Note note = card.note();
note.flush();
// flush card too, in case, did has been changed
card.flush();
}
Undoable changeDeckMulti = new UndoChangeDeckMulti(cards, originalDids);
// mark undo for all at once
col.markUndo(changeDeckMulti);
break;
}
case RESCHEDULE_CARDS:
case REPOSITION_CARDS:
case RESET_CARDS:
{
// collect undo information, sensitive to memory pressure, same for all 3 cases
try {
Timber.d("Saving undo information of type %s on %d cards", type, cards.length);
Card[] cards_copied = deepCopyCardArray(cards);
Undoable repositionRescheduleResetCards = new UndoRepositionRescheduleResetCards(type, cards_copied);
col.markUndo(repositionRescheduleResetCards);
} catch (CancellationException ce) {
Timber.i(ce, "Cancelled while handling type %s, skipping undo", type);
}
switch(type) {
case RESCHEDULE_CARDS:
sched.reschedCards(cardIds, (Integer) data[2], (Integer) data[2]);
break;
case REPOSITION_CARDS:
sched.sortCards(cardIds, (Integer) data[2], 1, false, true);
break;
case RESET_CARDS:
sched.forgetCards(cardIds);
break;
}
// In all cases schedule a new card so Reviewer doesn't sit on the old one
col.reset();
publishProgress(new TaskData(sched.getCard(), 0));
break;
}
}
col.getDb().getDatabase().setTransactionSuccessful();
} finally {
col.getDb().getDatabase().endTransaction();
}
} catch (RuntimeException e) {
Timber.e(e, "doInBackgroundSuspendCard - RuntimeException on suspending card");
AnkiDroidApp.sendExceptionReport(e, "doInBackgroundSuspendCard");
return new TaskData(false);
}
// (querying the cards again is unnecessarily expensive)
return new TaskData(true, cards);
}
use of com.ichi2.anki.Reviewer in project AnkiChinaAndroid by ankichinateam.
the class SchedV2 method currentCardIsInQueueWithDeck.
protected boolean currentCardIsInQueueWithDeck(@Consts.CARD_QUEUE int queue, long did) {
// mCurrentCard may be set to null when the reviewer gets closed. So we copy it to be sure to avoid NullPointerException
Card currentCard = mCurrentCard;
List<Long> currentCardParentsDid = mCurrentCardParentsDid;
return currentCard != null && currentCard.getQueue() == queue && currentCardParentsDid != null && currentCardParentsDid.contains(did);
}
Aggregations