Skip to content

Commit

Permalink
Decoupled Notification and Widget
Browse files Browse the repository at this point in the history
  • Loading branch information
prateek-singh-3212 committed Aug 14, 2021
1 parent d08acb2 commit a811f84
Show file tree
Hide file tree
Showing 5 changed files with 132 additions and 74 deletions.
18 changes: 12 additions & 6 deletions AnkiDroid/src/main/java/com/ichi2/anki/MetaDB.java
Original file line number Diff line number Diff line change
Expand Up @@ -438,12 +438,12 @@ public static void storeLookupDictionary(Context context, long did, int dictiona
}
}


/**
* Return the current status of the widget.
*
* @return [due, eta]
*/
* @return [due, eta] <br>
*<b> Widget Status table will be removed from database in future.</b>
* */
@Deprecated
public static int[] getWidgetSmallStatus(Context context) {
openDBIfClosed(context);
Cursor cursor = null;
Expand All @@ -463,7 +463,10 @@ public static int[] getWidgetSmallStatus(Context context) {
return new int[]{0, 0};
}


/**
* Widget Status table will be removed from database in future.
* */
@Deprecated
public static int getNotificationStatus(Context context) {
openDBIfClosed(context);
Cursor cursor = null;
Expand All @@ -483,7 +486,10 @@ public static int getNotificationStatus(Context context) {
return due;
}


/**
* Widget Status table will be removed from database in future.
* */
@Deprecated
public static void storeSmallWidgetStatus(Context context, Pair<Integer, Integer> status) {
openDBIfClosed(context);
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import com.ichi2.anki.Preferences;
import com.ichi2.anki.R;
import com.ichi2.compat.CompatHelper;
import com.ichi2.libanki.DecksMetaData;
import com.ichi2.widget.WidgetStatus;

import timber.log.Timber;
Expand All @@ -50,7 +51,7 @@ public void onReceive(Context context, Intent intent) {

SharedPreferences preferences = AnkiDroidApp.getSharedPrefs(context);
int minCardsDue = Integer.parseInt(preferences.getString(MINIMUM_CARDS_DUE_FOR_NOTIFICATION, Integer.toString(Preferences.PENDING_NOTIFICATIONS_ONLY)));
int dueCardsCount = WidgetStatus.fetchDue(context);
int dueCardsCount = new DecksMetaData(context).getTotalDueCards().first;
if (dueCardsCount >= minCardsDue) {
// Build basic notification
String cardsDueText = context.getResources()
Expand Down Expand Up @@ -86,4 +87,4 @@ public void onReceive(Context context, Intent intent) {
manager.cancel(WIDGET_NOTIFY_ID);
}
}
}
}
45 changes: 44 additions & 1 deletion AnkiDroid/src/main/java/com/ichi2/libanki/Deck.java
Original file line number Diff line number Diff line change
Expand Up @@ -62,4 +62,47 @@ public boolean isDyn() {
public boolean isStd() {
return getInt("dyn") == Consts.DECK_STD;
}
}

/**
* Time when deck is last modified.
* @return time in epoch
* */
public Long lastModified() {
return getLong("mod");
}

/**
* Retrieve all the learning card from the deck.
* @return Integer Array of size 2. index 0 is number of days that have passed between the collection was created </br>
* index 1 number of cards seen today in this deck minus the number of new cards
* */
public String[] lrnCards() {
return new String[] { getJSONArray("lrnToday").get(0).toString(), getJSONArray("lrnToday").get(1).toString()};
}

/**
* Retrieve all the new card from the deck.
* @return Integer Array of size 2. index 0 is number of days that have passed between the collection was created </br>
* index 1 number of cards seen today in this deck minus the number of new cards
* */
public String[] newCards() {
return new String[] { getJSONArray("newToday").get(0).toString(), getJSONArray("newToday").get(1).toString()};
}

/**
* Retrieve all the revision card from the deck.
* @return Integer Array of size 2. index 0 is number of days that have passed between the collection was created </br>
* index 1 number of cards seen today in this deck minus the number of new cards
* */
public String[] revCards() {
return new String[] {getJSONArray("revToday").get(0).toString(), getJSONArray("revToday").get(1).toString()};
}

/**
* Name of the deck.
* @return deck name
* */
public String deckName() {
return getString("name");
}
}
63 changes: 63 additions & 0 deletions AnkiDroid/src/main/java/com/ichi2/libanki/DecksMetaData.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* Copyright (c) 2021 Prateek Singh <[email protected]>
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 3 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/

package com.ichi2.libanki;

import android.content.Context;
import android.util.Log;
import android.util.Pair;
import android.widget.Toast;

import com.ichi2.anki.CollectionHelper;
import com.ichi2.libanki.sched.Counts;
import com.ichi2.libanki.sched.DeckDueTreeNode;

import java.util.Arrays;
import java.util.List;

public class DecksMetaData {

private final Decks mDecks;
private final Collection mCollection;

public DecksMetaData(Context context) {
mCollection = CollectionHelper.getInstance().getCol(context);
mDecks = mCollection.getDecks();
}

/**
* Total number of due cards and their expected time to compete.
* @return Pair of Total Due Cards and Expected time to complete. <br>
* <b>first</b> is due cards. <br>
* <b>second</b> is Expected time.
*/
public Pair<Integer, Integer> getTotalDueCards() {
Counts total = new Counts();
// Ensure queues are reset if we cross over to the next day.
mCollection.getSched()._checkDay();

// Only count the top-level decks in the total
List<DeckDueTreeNode> nodes = mCollection.getSched().deckDueTree();
for (DeckDueTreeNode node : nodes) {
total.addNew(node.getNewCount());
total.addLrn(node.getLrnCount());
total.addRev(node.getRevCount());
}
int eta = mCollection.getSched().eta(total, false);
Log.d("AABB", "getAllDeckNames: " + total.count() + " " + eta);
return new Pair<>(total.count(), eta);
}
}
75 changes: 10 additions & 65 deletions AnkiDroid/src/main/java/com/ichi2/widget/WidgetStatus.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,27 +15,15 @@
package com.ichi2.widget;

import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.util.Pair;

import androidx.localbroadcastmanager.content.LocalBroadcastManager;

import com.ichi2.anki.AnkiDroidApp;
import com.ichi2.anki.CollectionHelper;
import com.ichi2.anki.MetaDB;
import com.ichi2.anki.services.NotificationService;
import com.ichi2.async.BaseAsyncTask;
import com.ichi2.libanki.Collection;
import com.ichi2.libanki.sched.Counts;
import com.ichi2.libanki.sched.DeckDueTreeNode;

import java.util.List;
import com.ichi2.libanki.DecksMetaData;

import timber.log.Timber;

import static com.ichi2.anki.Preferences.MINIMUM_CARDS_DUE_FOR_NOTIFICATION;

/**
* The status of the widget.
*/
Expand All @@ -61,9 +49,8 @@ private WidgetStatus() {
public static void update(Context context) {
SharedPreferences preferences = AnkiDroidApp.getSharedPrefs(context);
sSmallWidgetEnabled = preferences.getBoolean("widgetSmallEnabled", false);
boolean notificationEnabled = Integer.parseInt(preferences.getString(MINIMUM_CARDS_DUE_FOR_NOTIFICATION, "1000001")) < 1000000;
boolean canExecuteTask = ((sUpdateDeckStatusAsyncTask == null) || (sUpdateDeckStatusAsyncTask.getStatus() == android.os.AsyncTask.Status.FINISHED));
if ((sSmallWidgetEnabled || notificationEnabled) && canExecuteTask) {
if (sSmallWidgetEnabled && canExecuteTask) {
Timber.d("WidgetStatus.update(): updating");
sUpdateDeckStatusAsyncTask = new UpdateDeckStatusAsyncTask();
sUpdateDeckStatusAsyncTask.execute(context);
Expand All @@ -73,68 +60,26 @@ public static void update(Context context) {
}


/** Returns the status of each of the decks. */
/** Returns the card due and eta of all the due decks. */
public static int[] fetchSmall(Context context) {
return MetaDB.getWidgetSmallStatus(context);
}


public static int fetchDue(Context context) {
return MetaDB.getNotificationStatus(context);
DecksMetaData metaData = new DecksMetaData(context);
Pair<Integer, Integer> pair = metaData.getTotalDueCards();
return new int[] {pair.first, pair.second};
}


private static class UpdateDeckStatusAsyncTask extends BaseAsyncTask<Context, Void, Context> {

// due, eta
private static Pair<Integer, Integer> sSmallWidgetStatus = new Pair<>(0, 0);

@Override
protected Context doInBackground(Context... params) {
super.doInBackground(params);
Timber.d("WidgetStatus.UpdateDeckStatusAsyncTask.doInBackground()");
Context context = params[0];
if (!AnkiDroidApp.isSdCardMounted()) {
if (!AnkiDroidApp.isSdCardMounted() && sSmallWidgetEnabled) {
return context;
}
try {
updateCounts(context);
} catch (Exception e) {
Timber.e(e, "Could not update widget");
}
return context;
}


@Override
protected void onPostExecute(Context context) {
super.onPostExecute(context);
Timber.d("WidgetStatus.UpdateDeckStatusAsyncTask.onPostExecute()");
MetaDB.storeSmallWidgetStatus(context, sSmallWidgetStatus);
if (sSmallWidgetEnabled) {
new AnkiDroidWidgetSmall.UpdateService().doUpdate(context);
}
Intent intent = new Intent(NotificationService.INTENT_ACTION);
Context appContext = context.getApplicationContext();
LocalBroadcastManager.getInstance(appContext).sendBroadcast(intent);
}


private void updateCounts(Context context) {
Counts total = new Counts();
Collection col = CollectionHelper.getInstance().getCol(context);
// Ensure queues are reset if we cross over to the next day.
col.getSched()._checkDay();
new AnkiDroidWidgetSmall.UpdateService().doUpdate(context);

// Only count the top-level decks in the total
List<DeckDueTreeNode> nodes = col.getSched().deckDueTree();
for (DeckDueTreeNode node : nodes) {
total.addNew(node.getNewCount());
total.addLrn(node.getLrnCount());
total.addRev(node.getRevCount());
}
int eta = col.getSched().eta(total, false);
sSmallWidgetStatus = new Pair<>(total.count(), eta);
return context;
}
}
}
}

0 comments on commit a811f84

Please sign in to comment.