Search in sources :

Example 6 with Sched

use of com.ichi2.libanki.sched.Sched in project AnkiChinaAndroid by ankichinateam.

the class CollectionTask method doInBackgroundUpdateNote.

private TaskData doInBackgroundUpdateNote(TaskData param) {
    Timber.d("doInBackgroundUpdateNote");
    // Save the note
    Collection col = getCol();
    AbstractSched sched = col.getSched();
    Card editCard = param.getCard();
    Note editNote = editCard.note();
    boolean fromReviewer = param.getBoolean();
    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.q(true);
                } else {
                    newCard = sched.getCard();
                }
                publishProgress(new TaskData(newCard));
            } else {
                publishProgress(new TaskData(editCard, editNote.stringTags()));
            }
            col.getDb().getDatabase().setTransactionSuccessful();
        } finally {
            col.getDb().getDatabase().endTransaction();
        }
    } catch (RuntimeException e) {
        Timber.e(e, "doInBackgroundUpdateNote - RuntimeException on updating note");
        AnkiDroidApp.sendExceptionReport(e, "doInBackgroundUpdateNote");
        return new TaskData(false);
    }
    return new TaskData(true);
}
Also used : AbstractSched(com.ichi2.libanki.sched.AbstractSched) Note(com.ichi2.libanki.Note) Collection(com.ichi2.libanki.Collection) Card(com.ichi2.libanki.Card)

Example 7 with Sched

use of com.ichi2.libanki.sched.Sched in project AnkiChinaAndroid by ankichinateam.

the class CollectionTask method nonTaskUndo.

@VisibleForTesting
public static Card nonTaskUndo(Collection col) {
    AbstractSched sched = col.getSched();
    Card card = col.undo();
    if (card == null) {
        /* multi-card action undone, no action to take here */
        Timber.d("Multi-select undo succeeded");
    } else {
        // cid is actually a card id.
        // a review was undone,
        /* card review undone, set up to review that card again */
        Timber.d("Single card review undo succeeded");
        card.startTimer();
        col.reset();
        sched.deferReset(card);
    }
    return card;
}
Also used : AbstractSched(com.ichi2.libanki.sched.AbstractSched) Card(com.ichi2.libanki.Card) VisibleForTesting(androidx.annotation.VisibleForTesting)

Example 8 with Sched

use of com.ichi2.libanki.sched.Sched 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 9 with Sched

use of com.ichi2.libanki.sched.Sched 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)

Example 10 with Sched

use of com.ichi2.libanki.sched.Sched in project AnkiChinaAndroid by ankichinateam.

the class CollectionTask method doInBackgroundUpdateValuesFromDeck.

private TaskData doInBackgroundUpdateValuesFromDeck(TaskData param) {
    Timber.d("doInBackgroundUpdateValuesFromDeck");
    try {
        Collection col = getCol();
        AbstractSched sched = col.getSched();
        Object[] obj = param.getObjArray();
        boolean reset = (Boolean) obj[0];
        if (reset) {
            // reset actually required because of counts, which is used in getCollectionTaskListener
            sched.resetCounts();
        }
        int[] counts = sched.counts();
        int totalNewCount = sched.totalNewForCurrentDeck();
        int totalCount = sched.cardCount();
        return new TaskData(new Object[] { counts[0], counts[1], counts[2], totalNewCount, totalCount, sched.eta(counts) });
    } catch (RuntimeException e) {
        Timber.e(e, "doInBackgroundUpdateValuesFromDeck - an error occurred");
        return null;
    }
}
Also used : AbstractSched(com.ichi2.libanki.sched.AbstractSched) Collection(com.ichi2.libanki.Collection) JSONObject(com.ichi2.utils.JSONObject)

Aggregations

Card (com.ichi2.libanki.Card)44 Collection (com.ichi2.libanki.Collection)38 Test (org.junit.Test)35 RobolectricTest (com.ichi2.anki.RobolectricTest)28 Note (com.ichi2.libanki.Note)19 AbstractSched (com.ichi2.libanki.sched.AbstractSched)18 DeckConfig (com.ichi2.libanki.DeckConfig)11 JSONObject (com.ichi2.utils.JSONObject)9 Cursor (android.database.Cursor)7 Sched (com.ichi2.libanki.Sched)6 SchedV2 (com.ichi2.libanki.sched.SchedV2)6 JSONArray (com.ichi2.utils.JSONArray)6 SuppressLint (android.annotation.SuppressLint)4 ConfirmModSchemaException (com.ichi2.anki.exception.ConfirmModSchemaException)4 DB (com.ichi2.libanki.DB)4 Model (com.ichi2.libanki.Model)4 Sched (com.ichi2.libanki.sched.Sched)4 ArrayList (java.util.ArrayList)4 Matchers.containsString (org.hamcrest.Matchers.containsString)4 ContentValues (android.content.ContentValues)3