Search in sources :

Example 1 with DeckDueTreeNode

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

the class StudyOptionsFragment method handleDeckSelection.

private void handleDeckSelection(long did, boolean dontSkipStudyOptions) {
    // Clear the undo history when selecting a new deck
    if (getCol().getDecks().selected() != did) {
        getCol().clearUndo();
    }
    // Select the deck
    getCol().getDecks().select(did);
    // Also forget the last deck used by the Browser
    CardBrowser.clearLastDeckId();
    // Reset the schedule so that we get the counts for the currently selected deck
    mFocusedDeck = did;
    // Get some info about the deck to handle special cases
    int pos = mDeckListAdapter.findDeckPosition(did);
    AbstractDeckTreeNode deckDueTreeNode = mDeckListAdapter.getDeckList().get(pos);
    // if (!deckDueTreeNode.shouldDisplayCounts() || deckDueTreeNode.knownToHaveRep()) {
    // If we don't yet have numbers, we trust the user that they knows what they opens, tries to open it.
    // If there is nothing to review, it'll come back to deck picker.
    openReviewerOrStudyOptions(dontSkipStudyOptions);
// return;
// }
// There are numbers
// Figure out what action to take
// if (getCol().getSched().hasCardsTodayAfterStudyAheadLimit()) {
// // If there are cards due that can't be studied yet (due to the learn ahead limit) then go to study options
// openStudyOptions(false);
// } else if (getCol().getSched().newDue() || getCol().getSched().revDue()) {
// // If there are no cards to review because of the daily study limit then give "Study more" option
// UIUtils.showSnackbar(getAnkiActivity(), R.string.studyoptions_limit_reached, false, R.string.study_more, v -> {
// CustomStudyDialog d = CustomStudyDialog.newInstance(
// CustomStudyDialog.CONTEXT_MENU_LIMITS,
// getCol().getDecks().selected(), true, this);
// showDialogFragment(d);
// }, getView().findViewById(R.id.root_layout), mSnackbarShowHideCallback);
// // Check if we need to update the fragment or update the deck list. The same checks
// // are required for all snackbars below.
// if (mFragmented) {
// // Tablets must always show the study options that corresponds to the current deck,
// // regardless of whether the deck is currently reviewable or not.
// openStudyOptions(false);
// } else {
// // On phones, we update the deck list to ensure the currently selected deck is
// // highlighted correctly.
// updateDeckList();
// }
// } else if (getCol().getDecks().isDyn(did)) {
// // Go to the study options screen if filtered deck with no cards to study
// openStudyOptions(false);
// } else if (!deckDueTreeNode.hasChildren() && getCol().cardCount(new Long[] {did}) == 0) {
// // If the deck is empty and has no children then show a message saying it's empty
// final Uri helpUrl = Uri.parse(getResources().getString(R.string.link_manual_getting_started));
// getAnkiActivity().mayOpenUrl(helpUrl);
// UIUtils.showSnackbar(getAnkiActivity(), R.string.empty_deck, false, R.string.help,
// v -> openHelpUrl(helpUrl), getView().findViewById(R.id.root_layout), mSnackbarShowHideCallback);
// if (mFragmented) {
// openStudyOptions(false);
// } else {
// updateDeckList();
// }
// } else {
// // Otherwise say there are no cards scheduled to study, and give option to do custom study
// UIUtils.showSnackbar(getAnkiActivity(), R.string.studyoptions_empty_schedule, false, R.string.custom_study, v -> {
// CustomStudyDialog d = CustomStudyDialog.newInstance(
// CustomStudyDialog.CONTEXT_MENU_EMPTY_SCHEDULE,
// getCol().getDecks().selected(), true, this);
// showDialogFragment(d);
// }, getView().findViewById(R.id.root_layout), mSnackbarShowHideCallback);
// if (mFragmented) {
// openStudyOptions(false);
// } else {
// updateDeckList();
// }
// }
}
Also used : AbstractDeckTreeNode(com.ichi2.libanki.sched.AbstractDeckTreeNode)

Example 2 with DeckDueTreeNode

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

the class ReminderService method onReceive.

@Override
public void onReceive(Context context, Intent intent) {
    cancelDeckReminder(context, intent);
    // 0 is not a valid dconf id.
    final long dConfId = intent.getLongExtra(EXTRA_DECK_OPTION_ID, 0);
    if (dConfId == 0) {
        Timber.w("onReceive - dConfId 0, returning");
        return;
    }
    CollectionHelper colHelper;
    Collection col;
    try {
        colHelper = CollectionHelper.getInstance();
        col = colHelper.getCol(context);
    } catch (Throwable t) {
        Timber.w("onReceive - unexpectedly unable to get collection. Returning.");
        return;
    }
    if (null == col || !colHelper.colIsOpen()) {
        Timber.w("onReceive - null or closed collection, unable to process reminders");
        return;
    }
    if (col.getDecks().getConf(dConfId) == null) {
        final AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
        final PendingIntent reminderIntent = PendingIntent.getBroadcast(context, (int) dConfId, new Intent(context, ReminderService.class).putExtra(EXTRA_DECK_OPTION_ID, dConfId), 0);
        alarmManager.cancel(reminderIntent);
    }
    final NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);
    if (!notificationManager.areNotificationsEnabled()) {
        Timber.v("onReceive - notifications disabled, returning");
        return;
    }
    List<DeckDueTreeNode> decksDue = getDeckOptionDue(col, dConfId, true);
    if (null == decksDue) {
        Timber.v("onReceive - no decks due, returning");
        return;
    }
    for (DeckDueTreeNode deckDue : decksDue) {
        long deckId = deckDue.getDid();
        final int total = deckDue.getRevCount() + deckDue.getLrnCount() + deckDue.getNewCount();
        if (total <= 0) {
            Timber.v("onReceive - no cards due in deck %d", deckId);
            continue;
        }
        Timber.v("onReceive - deck '%s' due count %d", deckDue.getFullDeckName(), total);
        final Notification notification = new NotificationCompat.Builder(context, NotificationChannels.getId(NotificationChannels.Channel.DECK_REMINDERS)).setCategory(NotificationCompat.CATEGORY_REMINDER).setContentTitle(context.getString(R.string.reminder_title)).setContentText(context.getResources().getQuantityString(R.plurals.reminder_text, total, deckDue.getFullDeckName(), total)).setSmallIcon(R.drawable.ic_stat_notify).setColor(ContextCompat.getColor(context, R.color.material_light_blue_700)).setContentIntent(PendingIntent.getActivity(context, (int) deckId, getReviewDeckIntent(context, deckId), PendingIntent.FLAG_UPDATE_CURRENT)).setAutoCancel(true).build();
        notificationManager.notify((int) deckId, notification);
        Timber.v("onReceive - notification state: %s", notification);
    }
}
Also used : NotificationManagerCompat(androidx.core.app.NotificationManagerCompat) Intent(android.content.Intent) PendingIntent(android.app.PendingIntent) Notification(android.app.Notification) DeckDueTreeNode(com.ichi2.libanki.sched.DeckDueTreeNode) Collection(com.ichi2.libanki.Collection) AlarmManager(android.app.AlarmManager) CollectionHelper(com.ichi2.anki.CollectionHelper) PendingIntent(android.app.PendingIntent)

Example 3 with DeckDueTreeNode

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

the class Sched method deckDueList.

/**
 * Returns [deckname, did, rev, lrn, new]
 */
@Override
@Nullable
public List<DeckDueTreeNode> deckDueList(@Nullable CollectionTask collectionTask, long did) {
    _checkDay();
    mCol.getDecks().checkIntegrity();
    ArrayList<Deck> decks = deckLimitWithParent(did, mCol);
    // ArrayList<Deck> decks = mCol.getDecks().allSorted();
    Timber.i("show decks" + did + " size:" + decks.size());
    HashMap<String, Integer[]> lims = new HashMap<>();
    ArrayList<DeckDueTreeNode> data = new ArrayList<>();
    long time = SystemClock.elapsedRealtime();
    for (Deck deck : decks) {
        if (collectionTask != null && collectionTask.isCancelled()) {
            return null;
        }
        String deckName = deck.getString("name");
        String p = Decks.parent(deckName);
        // new
        int nlim = _deckNewLimitSingle(deck);
        int rlim = _deckRevLimitSingle(deck);
        if (!TextUtils.isEmpty(p)) {
            Integer[] parentLims = lims.get(Decks.normalizeName(p));
            // 'temporary for diagnosis of bug #6383'
            Assert.that(parentLims != null, "Deck %s is supposed to have parent %s. It has not be found.", deckName, p);
            nlim = Math.min(nlim, parentLims[0]);
            // review
            rlim = Math.min(rlim, parentLims[1]);
        }
        // long time = SystemClock.elapsedRealtime();
        int _new = _newForDeck(deck.getLong("id"), nlim);
        // Timber.i("cost time for new:"+(SystemClock.elapsedRealtime()-time));
        // learning
        int lrn = _lrnForDeck(deck.getLong("id"));
        // Timber.i("cost time for lrn:"+(SystemClock.elapsedRealtime()-time));
        // reviews
        int rev = _revForDeck(deck.getLong("id"), rlim);
        // Timber.i("cost time for rev:"+(SystemClock.elapsedRealtime()-time));
        // save to list
        double[] datas = did == ALL_DECKS_ID ? _getCardDataCount(deck.getLong("id")) : new double[] { 0, 0, 0 };
        // Timber.i("cost time for datas:"+(SystemClock.elapsedRealtime()-time));
        // Timber.i("add deck in tree:%s", deckName);
        data.add(new DeckDueTreeNode(mCol, deck.getString("name"), deck.getLong("id"), rev, lrn, _new, datas));
        // add deck as a parent
        lims.put(Decks.normalizeName(deck.getString("name")), new Integer[] { nlim, rlim });
    }
    Timber.i("cost time for datas:" + (SystemClock.elapsedRealtime() - time));
    return data;
}
Also used : HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) Deck(com.ichi2.libanki.Deck) Nullable(androidx.annotation.Nullable)

Example 4 with DeckDueTreeNode

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

the class SchedV2 method deckDueList.

// Overridden
@Nullable
public List<DeckDueTreeNode> deckDueList(@Nullable CollectionTask collectionTask, long did) {
    _checkDay();
    mCol.getDecks().checkIntegrity();
    // ArrayList<Deck> decks = mCol.getDecks().allSorted();
    ArrayList<Deck> decks = deckLimitWithParent(did, mCol);
    Timber.i("show decks" + did + " size:" + decks.size());
    HashMap<String, Integer[]> lims = new HashMap<>();
    ArrayList<DeckDueTreeNode> data = new ArrayList<>();
    HashMap<Long, HashMap> childMap = mCol.getDecks().childMap();
    for (Deck deck : decks) {
        if (collectionTask != null && collectionTask.isCancelled()) {
            return null;
        }
        String deckName = deck.getString("name");
        String p = Decks.parent(deckName);
        // new
        int nlim = _deckNewLimitSingle(deck);
        Integer plim = null;
        if (!TextUtils.isEmpty(p)) {
            Integer[] parentLims = lims.get(Decks.normalizeName(p));
            // 'temporary for diagnosis of bug #6383'
            Assert.that(parentLims != null, "Deck %s is supposed to have parent %s. It has not be found.", deckName, p);
            nlim = Math.min(nlim, parentLims[0]);
            // reviews
            plim = parentLims[1];
        }
        int _new = _newForDeck(deck.getLong("id"), nlim);
        // learning
        int lrn = _lrnForDeck(deck.getLong("id"));
        // reviews
        int rlim = _deckRevLimitSingle(deck, plim);
        int rev = _revForDeck(deck.getLong("id"), rlim, childMap);
        double[] datas = did == ALL_DECKS_ID ? _getCardDataCount(deck.getLong("id")) : new double[] { 0, 0, 0 };
        // save to list
        // Timber.i("add deck in tree:%s", deckName);
        data.add(new DeckDueTreeNode(mCol, deck.getString("name"), deck.getLong("id"), rev, lrn, _new, datas));
        // add deck as a parent
        lims.put(Decks.normalizeName(deck.getString("name")), new Integer[] { nlim, rlim });
    }
    return data;
}
Also used : HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) Deck(com.ichi2.libanki.Deck) Nullable(androidx.annotation.Nullable)

Example 5 with DeckDueTreeNode

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

the class SchedTest method test_deckDueV1.

@Test
public void test_deckDueV1() throws Exception {
    Collection col = getColV1();
    // add a note with default deck
    Note note = col.newNote();
    note.setItem("Front", "one");
    col.addNote(note);
    // and one that's a child
    note = col.newNote();
    note.setItem("Front", "two");
    long default1 = col.getDecks().id("Default::1");
    note.model().put("did", default1);
    col.addNote(note);
    // make it a review card
    Card c = note.cards().get(0);
    c.setQueue(QUEUE_TYPE_REV);
    c.setDue(0);
    c.flush();
    // add one more with a new deck
    note = col.newNote();
    note.setItem("Front", "two");
    JSONObject foobar = note.model().put("did", col.getDecks().id("foo::bar"));
    col.addNote(note);
    // and one that's a sibling
    note = col.newNote();
    note.setItem("Front", "three");
    JSONObject foobaz = note.model().put("did", col.getDecks().id("foo::baz"));
    col.addNote(note);
    col.reset();
    assertEquals(5, col.getDecks().allSortedNames().size());
    DeckDueTreeNode tree = col.getSched().deckDueTree().get(0);
    assertEquals("Default", tree.getLastDeckNameComponent());
    // sum of child and parent
    assertEquals(1, tree.getDid());
    assertEquals(1, tree.getRevCount());
    assertEquals(1, tree.getNewCount());
    // child count is just review
    DeckDueTreeNode child = tree.getChildren().get(0);
    assertEquals("1", child.getLastDeckNameComponent());
    assertEquals(default1, child.getDid());
    assertEquals(1, child.getRevCount());
    assertEquals(0, child.getNewCount());
    // code should not fail if a card has an invalid deck
    c.setDid(12345);
    c.flush();
    col.getSched().deckDueTree();
}
Also used : DeckDueTreeNode(com.ichi2.libanki.sched.DeckDueTreeNode) JSONObject(com.ichi2.utils.JSONObject) Note(com.ichi2.libanki.Note) Collection(com.ichi2.libanki.Collection) Card(com.ichi2.libanki.Card) RobolectricTest(com.ichi2.anki.RobolectricTest) Test(org.junit.Test)

Aggregations

RobolectricTest (com.ichi2.anki.RobolectricTest)13 Test (org.junit.Test)13 Collection (com.ichi2.libanki.Collection)11 ArrayList (java.util.ArrayList)9 Card (com.ichi2.libanki.Card)8 Note (com.ichi2.libanki.Note)8 DeckDueTreeNode (com.ichi2.libanki.sched.DeckDueTreeNode)7 Deck (com.ichi2.libanki.Deck)6 JSONObject (com.ichi2.utils.JSONObject)6 Matchers.containsString (org.hamcrest.Matchers.containsString)6 Nullable (androidx.annotation.Nullable)5 Model (com.ichi2.libanki.Model)4 JSONArray (com.ichi2.utils.JSONArray)4 MatrixCursor (android.database.MatrixCursor)2 DeckConfig (com.ichi2.libanki.DeckConfig)2 JSONException (com.ichi2.utils.JSONException)2 HashMap (java.util.HashMap)2 List (java.util.List)2 AlarmManager (android.app.AlarmManager)1 Notification (android.app.Notification)1