use of com.ichi2.async.CollectionTask.TASK_TYPE.UNDO in project Anki-Android by Ramblurr.
the class DeckTask method doInBackgroundDismissNote.
private TaskData doInBackgroundDismissNote(TaskData... params) {
Sched sched = params[0].getSched();
Collection col = sched.getCol();
Card card = params[0].getCard();
Note note = card.note();
int type = params[0].getInt();
try {
col.getDb().getDatabase().beginTransaction();
try {
switch(type) {
case 4:
// collect undo information
col.markUndo(Collection.UNDO_BURY_CARD, new Object[] { col.getDirty(), note.cards(), card.getId() });
// then bury
sched.buryCards(new long[] { card.getId() });
sHadCardQueue = true;
break;
case 0:
// collect undo information
col.markUndo(Collection.UNDO_BURY_NOTE, new Object[] { col.getDirty(), note.cards(), card.getId() });
// then bury
sched.buryNote(note.getId());
sHadCardQueue = true;
break;
case 1:
// collect undo information
col.markUndo(Collection.UNDO_SUSPEND_CARD, new Object[] { card });
// suspend card
if (card.getQueue() == -1) {
sched.unsuspendCards(new long[] { card.getId() });
} else {
sched.suspendCards(new long[] { card.getId() });
}
sHadCardQueue = true;
break;
case 2:
// collect undo information
ArrayList<Card> cards = note.cards();
long[] cids = new long[cards.size()];
for (int i = 0; i < cards.size(); i++) {
cids[i] = cards.get(i).getId();
}
col.markUndo(Collection.UNDO_SUSPEND_NOTE, new Object[] { cards, card.getId() });
// suspend note
sched.suspendCards(cids);
sHadCardQueue = true;
break;
case 3:
// collect undo information
ArrayList<Card> allCs = note.cards();
long[] cardIds = new long[allCs.size()];
for (int i = 0; i < allCs.size(); i++) {
cardIds[i] = allCs.get(i).getId();
}
col.markUndo(Collection.UNDO_DELETE_NOTE, new Object[] { note, allCs, card.getId() });
// delete note
col.remNotes(new long[] { note.getId() });
sHadCardQueue = true;
break;
}
publishProgress(new TaskData(getCard(col.getSched()), 0));
col.getDb().getDatabase().setTransactionSuccessful();
} finally {
col.getDb().getDatabase().endTransaction();
}
} catch (RuntimeException e) {
Log.e(AnkiDroidApp.TAG, "doInBackgroundSuspendCard - RuntimeException on suspending card: " + e);
AnkiDroidApp.saveExceptionReportFile(e, "doInBackgroundSuspendCard");
return new TaskData(false);
}
return new TaskData(true);
}
use of com.ichi2.async.CollectionTask.TASK_TYPE.UNDO in project Anki-Android by Ramblurr.
the class DeckTask method doInBackgroundUpdateNote.
private TaskData doInBackgroundUpdateNote(TaskData[] params) {
// Log.i(AnkiDroidApp.TAG, "doInBackgroundUpdateNote");
// Save the note
Sched sched = params[0].getSched();
Collection col = sched.getCol();
Card editCard = params[0].getCard();
Note editNote = editCard.note();
boolean fromReviewer = params[0].getBoolean();
// mark undo
col.markUndo(Collection.UNDO_EDIT_NOTE, new Object[] { col.getNote(editNote.getId()), editCard.getId(), fromReviewer });
try {
col.getDb().getDatabase().beginTransaction();
try {
// TODO: undo integration
editNote.flush();
// flush card too, in case, did has been changed
editCard.flush();
if (fromReviewer) {
Card newCard;
if (col.getDecks().active().contains(editCard.getDid())) {
newCard = editCard;
newCard.load();
// reload qa-cache
newCard.getQuestion(true);
} else {
newCard = getCard(sched);
}
publishProgress(new TaskData(newCard));
} else {
publishProgress(new TaskData(editCard, editNote.stringTags()));
}
col.getDb().getDatabase().setTransactionSuccessful();
} finally {
col.getDb().getDatabase().endTransaction();
}
} catch (RuntimeException e) {
Log.e(AnkiDroidApp.TAG, "doInBackgroundUpdateNote - RuntimeException on updating fact: " + e);
AnkiDroidApp.saveExceptionReportFile(e, "doInBackgroundUpdateNote");
return new TaskData(false);
}
return new TaskData(true);
}
use of com.ichi2.async.CollectionTask.TASK_TYPE.UNDO in project Anki-Android by Ramblurr.
the class Connection method doInBackgroundSync.
private Payload doInBackgroundSync(Payload data) {
// for for doInBackgroundLoadDeckCounts if any
DeckTask.waitToFinish();
String hkey = (String) data.data[0];
boolean media = (Boolean) data.data[1];
String conflictResolution = (String) data.data[2];
int mediaUsn = (Integer) data.data[3];
boolean colCorruptFullSync = false;
Collection col = AnkiDroidApp.getCol();
if (!AnkiDroidApp.colIsOpen()) {
if (conflictResolution != null && conflictResolution.equals("download")) {
colCorruptFullSync = true;
} else {
data.success = false;
data.result = new Object[] { "genericError" };
return data;
}
}
String path = AnkiDroidApp.getCollectionPath();
BasicHttpSyncer server = new RemoteServer(this, hkey);
Syncer client = new Syncer(col, server);
// run sync and check state
boolean noChanges = false;
if (conflictResolution == null) {
// Log.i(AnkiDroidApp.TAG, "Sync - starting sync");
publishProgress(R.string.sync_prepare_syncing);
Object[] ret = client.sync(this);
data.message = client.getSyncMsg();
mediaUsn = client.getmMediaUsn();
if (ret == null) {
data.success = false;
data.result = new Object[] { "genericError" };
return data;
}
String retCode = (String) ret[0];
if (!retCode.equals("noChanges") && !retCode.equals("success")) {
data.success = false;
data.result = ret;
// note mediaUSN for later
data.data = new Object[] { mediaUsn };
return data;
}
// save and note success state
if (retCode.equals("noChanges")) {
// publishProgress(R.string.sync_no_changes_message);
noChanges = true;
} else {
// publishProgress(R.string.sync_database_success);
}
} else {
try {
server = new FullSyncer(col, hkey, this);
if (conflictResolution.equals("upload")) {
// Log.i(AnkiDroidApp.TAG, "Sync - fullsync - upload collection");
publishProgress(R.string.sync_preparing_full_sync_message);
Object[] ret = server.upload();
if (ret == null) {
data.success = false;
data.result = new Object[] { "genericError" };
AnkiDroidApp.openCollection(path);
return data;
}
if (!((String) ret[0]).equals(BasicHttpSyncer.ANKIWEB_STATUS_OK)) {
data.success = false;
data.result = ret;
AnkiDroidApp.openCollection(path);
return data;
}
} else if (conflictResolution.equals("download")) {
// Log.i(AnkiDroidApp.TAG, "Sync - fullsync - download collection");
publishProgress(R.string.sync_downloading_message);
Object[] ret = server.download();
if (ret == null) {
data.success = false;
data.result = new Object[] { "genericError" };
AnkiDroidApp.openCollection(path);
return data;
}
if (!((String) ret[0]).equals("success")) {
data.success = false;
data.result = ret;
if (!colCorruptFullSync) {
AnkiDroidApp.openCollection(path);
}
return data;
}
}
col = AnkiDroidApp.openCollection(path);
} catch (OutOfMemoryError e) {
AnkiDroidApp.saveExceptionReportFile(e, "doInBackgroundSync-fullSync");
data.success = false;
data.result = new Object[] { "OutOfMemoryError" };
data.data = new Object[] { mediaUsn };
return data;
} catch (RuntimeException e) {
AnkiDroidApp.saveExceptionReportFile(e, "doInBackgroundSync-fullSync");
data.success = false;
data.result = new Object[] { "IOException" };
data.data = new Object[] { mediaUsn };
return data;
}
}
// clear undo to avoid non syncing orphans (because undo resets usn too
if (!noChanges) {
col.clearUndo();
}
// then move on to media sync
boolean noMediaChanges = false;
String mediaError = null;
if (media) {
server = new RemoteMediaServer(hkey, this);
MediaSyncer mediaClient = new MediaSyncer(col, (RemoteMediaServer) server);
String ret;
try {
ret = mediaClient.sync(mediaUsn, this);
if (ret == null) {
mediaError = AnkiDroidApp.getAppResources().getString(R.string.sync_media_error);
} else {
if (ret.equals("noChanges")) {
publishProgress(R.string.sync_media_no_changes);
noMediaChanges = true;
}
if (ret.equals("sanityFailed")) {
mediaError = AnkiDroidApp.getAppResources().getString(R.string.sync_media_sanity_failed);
} else {
publishProgress(R.string.sync_media_success);
}
}
} catch (RuntimeException e) {
AnkiDroidApp.saveExceptionReportFile(e, "doInBackgroundSync-mediaSync");
mediaError = e.getLocalizedMessage();
}
}
if (noChanges && noMediaChanges) {
data.success = false;
data.result = new Object[] { "noChanges" };
return data;
} else {
data.success = true;
TreeSet<Object[]> decks = col.getSched().deckDueTree();
int[] counts = new int[] { 0, 0, 0 };
for (Object[] deck : decks) {
if (((String[]) deck[0]).length == 1) {
counts[0] += (Integer) deck[2];
counts[1] += (Integer) deck[3];
counts[2] += (Integer) deck[4];
}
}
Object[] dc = col.getSched().deckCounts();
data.result = dc[0];
data.data = new Object[] { conflictResolution, col, dc[1], dc[2], mediaError };
return data;
}
}
use of com.ichi2.async.CollectionTask.TASK_TYPE.UNDO in project AnkiChinaAndroid by ankichinateam.
the class SelfStudyActivity method onOptionsItemSelected.
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// (when another operation will be performed on the model, it will undo the latest operation)
if (mUndoSnackbar != null && mUndoSnackbar.isShown()) {
mUndoSnackbar.dismiss();
}
switch(item.getItemId()) {
case android.R.id.home:
endMultiSelectMode();
return true;
case R.id.screen:
showScreenDialog();
return true;
case R.id.action_edit:
mCardsAdapter.setMultiCheckable(!mCardsAdapter.isMultiCheckableMode());
return true;
case R.id.action_add_note_from_card_browser:
{
Intent intent = new Intent(SelfStudyActivity.this, NoteEditor.class);
intent.putExtra(NoteEditor.EXTRA_CALLER, NoteEditor.CALLER_CARDBROWSER_ADD);
startActivityForResultWithAnimation(intent, ADD_NOTE, ActivityTransitionAnimation.LEFT);
return true;
}
case R.id.action_save_search:
{
String searchTerms = mSearchView.getQuery().toString();
showDialogFragment(CardBrowserMySearchesDialog.newInstance(null, mMySearchesDialogListener, searchTerms, CardBrowserMySearchesDialog.CARD_BROWSER_MY_SEARCHES_TYPE_SAVE));
return true;
}
case R.id.action_list_my_searches:
{
JSONObject savedFiltersObj = getCol().getConf().optJSONObject("savedFilters");
HashMap<String, String> savedFilters = new HashMap<>();
if (savedFiltersObj != null) {
Iterator<String> it = savedFiltersObj.keys();
while (it.hasNext()) {
String searchName = it.next();
savedFilters.put(searchName, savedFiltersObj.optString(searchName));
}
}
showDialogFragment(CardBrowserMySearchesDialog.newInstance(savedFilters, mMySearchesDialogListener, "", CardBrowserMySearchesDialog.CARD_BROWSER_MY_SEARCHES_TYPE_LIST));
return true;
}
case R.id.action_sort_by_size:
showDialogFragment(CardBrowserOrderDialog.newInstance(mOrder, mOrderAsc, mOrderDialogListener));
return true;
case R.id.action_show_marked:
mSearchTerms = "tag:marked";
mSearchView.setQuery("", false);
mSearchView.setQueryHint(getResources().getString(R.string.card_browser_show_marked));
searchCards();
return true;
case R.id.action_show_suspended:
mSearchTerms = "is:suspended";
mSearchView.setQuery("", false);
mSearchView.setQueryHint(getResources().getString(R.string.card_browser_show_suspended));
searchCards();
return true;
case R.id.action_flag_zero:
flagTask(0);
return true;
case R.id.action_flag_one:
flagTask(1);
return true;
case R.id.action_flag_two:
flagTask(2);
return true;
case R.id.action_flag_three:
flagTask(3);
return true;
case R.id.action_flag_four:
flagTask(4);
return true;
case R.id.action_delete_card:
if (inMultiSelectMode()) {
CollectionTask.launchCollectionTask(DISMISS_MULTI, mDeleteNoteHandler, new TaskData(new Object[] { getSelectedCardIds(), Collection.DismissType.DELETE_NOTE_MULTI }));
mCardsAdapter.getSelectedItemIds().clear();
}
return true;
case R.id.action_mark_card:
CollectionTask.launchCollectionTask(DISMISS_MULTI, markCardHandler(), new TaskData(new Object[] { getSelectedCardIds(), Collection.DismissType.MARK_NOTE_MULTI }));
return true;
case R.id.action_suspend_card:
CollectionTask.launchCollectionTask(DISMISS_MULTI, suspendCardHandler(), new TaskData(new Object[] { getSelectedCardIds(), Collection.DismissType.SUSPEND_CARD_MULTI }));
toggleMultiSelectMode(false);
return true;
case R.id.action_change_deck:
{
AlertDialog.Builder builderSingle = new AlertDialog.Builder(this);
builderSingle.setTitle(getString(R.string.move_all_to_deck));
// WARNING: changeDeck depends on this index, so any changes should be reflected there.
final ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(this, R.layout.dropdown_deck_item);
for (Deck deck : getValidDecksForChangeDeck()) {
try {
arrayAdapter.add(deck.getString("name"));
} catch (JSONException e) {
e.printStackTrace();
}
}
builderSingle.setNegativeButton(getString(R.string.cancel), (dialog, which) -> dialog.dismiss());
builderSingle.setAdapter(arrayAdapter, (dialog, which) -> changeDeck(which));
builderSingle.show();
return true;
}
case R.id.action_undo:
if (getCol().undoAvailable()) {
CollectionTask.launchCollectionTask(UNDO, mUndoHandler);
}
return true;
case R.id.action_preview:
{
mStartStudyButton.performClick();
return true;
}
case R.id.action_reset_cards_progress:
{
Timber.i("NoteEditor:: Reset progress button pressed");
// Show confirmation dialog before resetting card progress
ConfirmationDialog dialog = new ConfirmationDialog();
String title = getString(R.string.reset_card_dialog_title);
String message = getString(R.string.reset_card_dialog_message);
dialog.setArgs(title, message);
Runnable confirm = () -> {
Timber.i("CardBrowser:: ResetProgress button pressed");
CollectionTask.launchCollectionTask(DISMISS_MULTI, resetProgressCardHandler(), new TaskData(new Object[] { getSelectedCardIds(), Collection.DismissType.RESET_CARDS }));
};
dialog.setConfirm(confirm);
showDialogFragment(dialog);
return true;
}
case R.id.action_reschedule_cards:
{
Timber.i("CardBrowser:: Reschedule button pressed");
long[] selectedCardIds = getSelectedCardIds();
FunctionalInterfaces.Consumer<Integer> consumer = newDays -> CollectionTask.launchCollectionTask(DISMISS_MULTI, rescheduleCardHandler(), new TaskData(new Object[] { selectedCardIds, Collection.DismissType.RESCHEDULE_CARDS, newDays }));
RescheduleDialog rescheduleDialog;
if (selectedCardIds.length == 1) {
long cardId = selectedCardIds[0];
Card selected = getCol().getCard(cardId);
rescheduleDialog = RescheduleDialog.rescheduleSingleCard(getResources(), selected, consumer);
} else {
rescheduleDialog = RescheduleDialog.rescheduleMultipleCards(getResources(), consumer, selectedCardIds.length);
}
showDialogFragment(rescheduleDialog);
return true;
}
case R.id.action_reposition_cards:
{
Timber.i("CardBrowser:: Reposition button pressed");
// Only new cards may be repositioned
long[] cardIds = getSelectedCardIds();
for (int i = 0; i < cardIds.length; i++) {
if (getCol().getCard(cardIds[i]).getQueue() != Consts.CARD_TYPE_NEW) {
SimpleMessageDialog dialog = SimpleMessageDialog.newInstance(getString(R.string.vague_error), getString(R.string.reposition_card_not_new_error), false);
showDialogFragment(dialog);
return false;
}
}
IntegerDialog repositionDialog = new IntegerDialog();
repositionDialog.setArgs(getString(R.string.reposition_card_dialog_title), getString(R.string.reposition_card_dialog_message), 5);
repositionDialog.setCallbackRunnable(days -> CollectionTask.launchCollectionTask(DISMISS_MULTI, repositionCardHandler(), new TaskData(new Object[] { cardIds, Collection.DismissType.REPOSITION_CARDS, days })));
showDialogFragment(repositionDialog);
return true;
}
case R.id.action_edit_note:
{
openNoteEditorForCurrentlySelectedNote();
}
default:
return super.onOptionsItemSelected(item);
}
}
use of com.ichi2.async.CollectionTask.TASK_TYPE.UNDO in project AnkiChinaAndroid by ankichinateam.
the class StudyOptionsFragment method onMenuItemClick.
@SuppressWarnings("deprecation")
@Override
public boolean onMenuItemClick(MenuItem item) {
switch(item.getItemId()) {
case R.id.action_browser:
{
Timber.i("DeckPicker:: Old browser button pressed");
getAnkiActivity().openOldCardBrowser();
return true;
}
case R.id.action_undo:
Timber.i("StudyOptionsFragment:: Undo button pressed");
CollectionTask.launchCollectionTask(UNDO, undoListener);
return true;
case R.id.action_deck_options:
Timber.i("StudyOptionsFragment:: Deck options button pressed");
if (getCol().getDecks().isDyn(getCol().getDecks().selected())) {
openFilteredDeckOptions();
} else {
Intent i = new Intent(getActivity(), DeckOptions.class);
getActivity().startActivityForResult(i, DECK_OPTIONS);
ActivityTransitionAnimation.slide(getActivity(), ActivityTransitionAnimation.FADE);
}
return true;
case R.id.action_setting:
Timber.i("StudyOptionsFragment:: Deck setting button pressed");
Intent i = new Intent(getActivity(), StudySettingActivity.class);
getActivity().startActivityForResult(i, DECK_OPTIONS);
ActivityTransitionAnimation.slide(getActivity(), ActivityTransitionAnimation.FADE);
return true;
case R.id.action_custom_study:
Timber.i("StudyOptionsFragment:: custom study button pressed");
showCustomStudyContextMenu();
return true;
case R.id.action_unbury:
Timber.i("StudyOptionsFragment:: unbury button pressed");
getCol().getSched().unburyCardsForDeck();
refreshInterfaceAndDecklist(true);
item.setVisible(false);
return true;
case R.id.action_rebuild:
Timber.i("StudyOptionsFragment:: rebuild cram deck button pressed");
mProgressDialog = StyledProgressDialog.show(getActivity(), "", getResources().getString(R.string.rebuild_filtered_deck), true);
CollectionTask.launchCollectionTask(REBUILD_CRAM, getCollectionTaskListener(true));
return true;
case R.id.action_empty:
Timber.i("StudyOptionsFragment:: empty cram deck button pressed");
mProgressDialog = StyledProgressDialog.show(getActivity(), "", getResources().getString(R.string.empty_filtered_deck), false);
CollectionTask.launchCollectionTask(EMPTY_CRAM, getCollectionTaskListener(true));
return true;
case R.id.action_rename:
((AnkiActivity) getActivity()).renameDeckDialog(getCol().getDecks().selected());
return true;
case R.id.action_delete:
getAnkiActivity().mContextMenuDid = getCol().getDecks().selected();
((AnkiActivity) getActivity()).confirmDeckDeletion(getCol().getDecks().selected());
return true;
case R.id.action_export:
((AnkiActivity) getActivity()).exportDeck(getCol().getDecks().selected());
return true;
case R.id.action_add_card:
addNote();
return true;
case R.id.create_deck:
getAnkiActivity().mContextMenuDid = getCol().getDecks().selected();
((AnkiActivity) getActivity()).createSubdeckDialog();
return true;
case // 停止/恢复
R.id.action_suspend:
mDeckIsStopped = deckIsStopped();
if (mDeckIsStopped) {
customDialog = new CustomStyleDialog.Builder(getAnkiActivity()).setTitle("恢复学习").setMessage("恢复学习后将每天新卡数和复习数值调整成默认值,请确认是否开始学习").setPositiveButton("确定", (dialog, which) -> {
resumeDeckStudy();
dialog.dismiss();
}).setNegativeButton("取消", (dialog, which) -> dialog.dismiss()).create();
} else {
customDialog = new CustomStyleDialog.Builder(getAnkiActivity()).setTitle("停止学习").setMessage("暂停学习将会自动把每天新卡数和复习数调整为零,适用于有事暂停一两周不学习,若该记忆库学习的时长不超过2个月,又暂停了30天未学习,建议重设进度,重新开始学习").setPositiveButton("确定", (dialog, which) -> {
stopDeckStudy();
dialog.dismiss();
}).setNegativeButton("取消", (dialog, which) -> dialog.dismiss()).create();
}
customDialog.show();
return true;
case // 重设学习进度
R.id.action_reset_card_progress:
customDialog = new CustomStyleDialog.Builder(getAnkiActivity()).setTitle("重设学习进度").setMessage("重设学习进度后,该记忆库的所有卡片学习记录都会被清除,请谨慎操作").setPositiveButton("确定", (dialog, which) -> {
CollectionTask.launchCollectionTask(RESET_DECK, new ResetCardHandler(StudyOptionsFragment.this), new TaskData(new Object[] { "deck:\"" + getCol().getDecks().current().getString("name") + "\" " }));
dialog.dismiss();
}).setNegativeButton("取消", (dialog, which) -> dialog.dismiss()).create();
customDialog.show();
return true;
default:
return false;
}
}
Aggregations