Search in sources :

Example 26 with TaskData

use of com.ichi2.async.TaskData 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);
}
Also used : Undoable(com.ichi2.libanki.Undoable) Set(java.util.Set) AbstractSched(com.ichi2.libanki.sched.AbstractSched) ArrayList(java.util.ArrayList) List(java.util.List) ArrayList(java.util.ArrayList) LinkedList(java.util.LinkedList) Deck(com.ichi2.libanki.Deck) JSONException(com.ichi2.utils.JSONException) CancellationException(java.util.concurrent.CancellationException) FileNotFoundException(java.io.FileNotFoundException) ConfirmModSchemaException(com.ichi2.anki.exception.ConfirmModSchemaException) ImportExportException(com.ichi2.anki.exception.ImportExportException) IOException(java.io.IOException) ExecutionException(java.util.concurrent.ExecutionException) Card(com.ichi2.libanki.Card) CancellationException(java.util.concurrent.CancellationException) Note(com.ichi2.libanki.Note) Collection(com.ichi2.libanki.Collection) JSONObject(com.ichi2.utils.JSONObject)

Example 27 with TaskData

use of com.ichi2.async.TaskData in project AnkiChinaAndroid by ankichinateam.

the class CollectionTask method doInBackGroundDeleteField.

/**
 * Deletes thje given field in the given model
 */
private TaskData doInBackGroundDeleteField(TaskData param) {
    Timber.d("doInBackGroundDeleteField");
    Object[] objects = param.getObjArray();
    Model model = (Model) objects[0];
    JSONObject field = (JSONObject) objects[1];
    Collection col = getCol();
    try {
        col.getModels().remField(model, field);
        col.save();
    } catch (ConfirmModSchemaException e) {
        // Should never be reached
        return new TaskData(false);
    }
    return new TaskData(true);
}
Also used : JSONObject(com.ichi2.utils.JSONObject) Model(com.ichi2.libanki.Model) TemporaryModel(com.ichi2.anki.TemporaryModel) Collection(com.ichi2.libanki.Collection) ConfirmModSchemaException(com.ichi2.anki.exception.ConfirmModSchemaException) JSONObject(com.ichi2.utils.JSONObject)

Example 28 with TaskData

use of com.ichi2.async.TaskData in project AnkiChinaAndroid by ankichinateam.

the class CollectionTask method doInBackgroundExportApkg.

private TaskData doInBackgroundExportApkg(TaskData param) {
    Timber.d("doInBackgroundExportApkg");
    Object[] data = param.getObjArray();
    Collection col = (Collection) data[0];
    String apkgPath = (String) data[1];
    Long did = (Long) data[2];
    boolean includeSched = (Boolean) data[3];
    boolean includeMedia = (Boolean) data[4];
    boolean exportApkg = (Boolean) data[5];
    boolean exportCard = (Boolean) data[6];
    try {
        AnkiPackageExporter exporter = new AnkiPackageExporter(col);
        exporter.setIncludeSched(includeSched);
        exporter.setIncludeMedia(includeMedia);
        exporter.setExportCard(exportCard);
        exporter.setExportApkg(exportApkg);
        exporter.setDid(did);
        exporter.exportInto(apkgPath, mContext);
    } catch (FileNotFoundException e) {
        Timber.e(e, "FileNotFoundException in doInBackgroundExportApkg");
        return new TaskData(false);
    } catch (IOException e) {
        Timber.e(e, "IOException in doInBackgroundExportApkg");
        return new TaskData(false);
    } catch (JSONException e) {
        Timber.e(e, "JSOnException in doInBackgroundExportApkg");
        return new TaskData(false);
    } catch (ImportExportException e) {
        Timber.e(e, "ImportExportException in doInBackgroundExportApkg");
        return new TaskData(e.getMessage(), true);
    }
    return new TaskData(exportCard ? apkgPath.replace(".apkg", ".card") : apkgPath);
}
Also used : FileNotFoundException(java.io.FileNotFoundException) JSONException(com.ichi2.utils.JSONException) IOException(java.io.IOException) AnkiPackageExporter(com.ichi2.libanki.AnkiPackageExporter) ImportExportException(com.ichi2.anki.exception.ImportExportException) Collection(com.ichi2.libanki.Collection) JSONObject(com.ichi2.utils.JSONObject)

Example 29 with TaskData

use of com.ichi2.async.TaskData in project AnkiChinaAndroid by ankichinateam.

the class CollectionTask method doInBackgroundCheckMedia.

/**
 * @return The results list from the check, or false if any errors.
 */
private TaskData doInBackgroundCheckMedia() {
    Timber.d("doInBackgroundCheckMedia");
    Collection col = getCol();
    // A media check on AnkiDroid will also update the media db
    col.getMedia().findChanges(true);
    // Then do the actual check
    List<List<String>> result = col.getMedia().check();
    return new TaskData(0, new Object[] { result }, true);
}
Also used : Collection(com.ichi2.libanki.Collection) List(java.util.List) ArrayList(java.util.ArrayList) LinkedList(java.util.LinkedList)

Example 30 with TaskData

use of com.ichi2.async.TaskData in project AnkiChinaAndroid by ankichinateam.

the class CollectionTask method doInBackgroundResetDeck.

private TaskData doInBackgroundResetDeck(TaskData param) {
    Timber.d("doInBackgroundSearchCardIds");
    Collection col = getCol();
    String query = (String) param.getObjArray()[0];
    if (isCancelled()) {
        Timber.d("doInBackgroundSearchCards was cancelled so return null");
        return null;
    }
    List<Long> searchResult_ = col.findCards(query, true, this);
    long[] cardIds = new long[searchResult_.size()];
    Card[] cards = new Card[searchResult_.size()];
    for (int i = 0; i < searchResult_.size(); i++) {
        cardIds[i] = searchResult_.get(i);
        cards[i] = col.getCard(searchResult_.get(i));
    }
    try {
        col.getDb().getDatabase().beginTransaction();
        try {
            try {
                Timber.d("Saving undo information of type %s on %d cards", RESET_CARDS, cards.length);
                Card[] cards_copied = deepCopyCardArray(cards);
                Undoable repositionRescheduleResetCards = new UndoRepositionRescheduleResetCards(RESET_CARDS, cards_copied);
                col.markUndo(repositionRescheduleResetCards);
            } catch (CancellationException ce) {
                Timber.i(ce, "Cancelled while handling type %s, skipping undo", RESET_CARDS);
            }
            AbstractSched sched = col.getSched();
            sched.forgetCards(cardIds);
            col.reset();
            publishProgress(new TaskData(sched.getCard(), 0));
            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);
    }
    return new TaskData(true, cards);
}
Also used : Undoable(com.ichi2.libanki.Undoable) AbstractSched(com.ichi2.libanki.sched.AbstractSched) Card(com.ichi2.libanki.Card) CancellationException(java.util.concurrent.CancellationException) Collection(com.ichi2.libanki.Collection)

Aggregations

Collection (com.ichi2.libanki.Collection)67 TaskData (com.ichi2.async.TaskData)46 JSONObject (com.ichi2.utils.JSONObject)35 Card (com.ichi2.libanki.Card)16 JSONException (com.ichi2.utils.JSONException)15 ArrayList (java.util.ArrayList)14 JSONObject (org.json.JSONObject)13 Resources (android.content.res.Resources)12 HashMap (java.util.HashMap)12 SharedPreferences (android.content.SharedPreferences)11 Deck (com.ichi2.libanki.Deck)11 Intent (android.content.Intent)10 View (android.view.View)9 TextView (android.widget.TextView)9 ConfirmationDialog (com.ichi2.anki.dialogs.ConfirmationDialog)9 TaskListener (com.ichi2.async.TaskListener)9 Map (java.util.Map)9 VisibleForTesting (androidx.annotation.VisibleForTesting)8 CollectionTask (com.ichi2.async.CollectionTask)8 IOException (java.io.IOException)8