Search in sources :

Example 6 with AbstractSched

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

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

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

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

Example 10 with AbstractSched

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

the class Collection method createScheduler.

// This duplicates _loadScheduler (but returns the value and sets the report limit).
public AbstractSched createScheduler(int reportLimit) {
    int ver = schedVer();
    if (ver == 1) {
        mSched = new Sched(this);
    } else if (ver == 2) {
        mSched = new SchedV2(this);
    }
    mSched.setReportLimit(reportLimit);
    return mSched;
}
Also used : AbstractSched(com.ichi2.libanki.sched.AbstractSched) Sched(com.ichi2.libanki.sched.Sched) SuppressLint(android.annotation.SuppressLint) SchedV2(com.ichi2.libanki.sched.SchedV2)

Aggregations

Card (com.ichi2.libanki.Card)28 Collection (com.ichi2.libanki.Collection)28 Test (org.junit.Test)23 AbstractSched (com.ichi2.libanki.sched.AbstractSched)19 RobolectricTest (com.ichi2.anki.RobolectricTest)18 Note (com.ichi2.libanki.Note)12 DeckConfig (com.ichi2.libanki.DeckConfig)9 JSONObject (com.ichi2.utils.JSONObject)9 Deck (com.ichi2.libanki.Deck)5 JSONArray (com.ichi2.utils.JSONArray)5 Cursor (android.database.Cursor)4 DB (com.ichi2.libanki.DB)4 Model (com.ichi2.libanki.Model)4 Matchers.containsString (org.hamcrest.Matchers.containsString)4 Models (com.ichi2.libanki.Models)3 Undoable (com.ichi2.libanki.Undoable)3 Sched (com.ichi2.libanki.sched.Sched)3 SchedV2 (com.ichi2.libanki.sched.SchedV2)3 JSONException (com.ichi2.utils.JSONException)3 SuppressLint (android.annotation.SuppressLint)2