Skip to content

Commit

Permalink
Refactored Small widget
Browse files Browse the repository at this point in the history
  • Loading branch information
prateek-singh-3212 committed Aug 24, 2021
1 parent c72be85 commit 9f38230
Show file tree
Hide file tree
Showing 14 changed files with 163 additions and 61 deletions.
5 changes: 5 additions & 0 deletions AnkiDroid/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,11 @@
/>
</receiver>

<!-- Small Widget Update Alarm-->
<receiver android:name="com.ichi2.widget.WidgetAlarm"
android:enabled="true"
android:exported="true"/>

<!-- "Add Note" widget -->
<receiver
android:name="com.ichi2.widget.AddNoteWidget"
Expand Down
2 changes: 0 additions & 2 deletions AnkiDroid/src/main/java/com/ichi2/anki/CardBrowser.java
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,6 @@
import com.ichi2.utils.LanguageUtil;
import com.ichi2.utils.Computation;
import com.ichi2.utils.Permissions;
import com.ichi2.widget.WidgetStatus;

import com.ichi2.utils.JSONException;
import com.ichi2.utils.JSONObject;
Expand Down Expand Up @@ -899,7 +898,6 @@ protected void onStop() {
// cancel rendering the question and answer, which has shared access to mCards
super.onStop();
if (!isFinishing()) {
WidgetStatus.update(this);
UIUtils.saveCollectionInBackground();
}
}
Expand Down
3 changes: 0 additions & 3 deletions AnkiDroid/src/main/java/com/ichi2/anki/DeckPicker.java
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,6 @@
import com.ichi2.utils.SyncStatus;
import com.ichi2.utils.Triple;
import com.ichi2.utils.VersionUtils;
import com.ichi2.widget.WidgetStatus;

import com.ichi2.utils.JSONException;

Expand Down Expand Up @@ -998,7 +997,6 @@ protected void onStop() {
Timber.d("onStop()");
super.onStop();
if (colIsOpen()) {
WidgetStatus.update(this);
// Ignore the modification - a change in deck shouldn't trigger the icon for "pending changes".
UIUtils.saveCollectionInBackground(true);
}
Expand Down Expand Up @@ -1972,7 +1970,6 @@ public void onPostExecute(Payload data) {
supportInvalidateOptionsMenu();

updateDeckList();
WidgetStatus.update(DeckPicker.this);
if (mFragmented) {
try {
loadStudyOptionsFragment(false);
Expand Down
2 changes: 0 additions & 2 deletions AnkiDroid/src/main/java/com/ichi2/anki/ModelBrowser.java
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@
import com.ichi2.libanki.Model;
import com.ichi2.libanki.StdModels;
import com.ichi2.ui.FixedEditText;
import com.ichi2.widget.WidgetStatus;

import java.util.ArrayList;
import java.util.Random;
Expand Down Expand Up @@ -221,7 +220,6 @@ public boolean onOptionsItemSelected(MenuItem item) {
public void onStop() {
super.onStop();
if (!isFinishing()) {
WidgetStatus.update(this);
UIUtils.saveCollectionInBackground();
}
}
Expand Down
2 changes: 0 additions & 2 deletions AnkiDroid/src/main/java/com/ichi2/anki/ModelFieldEditor.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@
import com.ichi2.libanki.Model;
import com.ichi2.themes.StyledProgressDialog;
import com.ichi2.ui.FixedEditText;
import com.ichi2.widget.WidgetStatus;

import com.ichi2.utils.JSONArray;
import com.ichi2.utils.JSONException;
Expand Down Expand Up @@ -105,7 +104,6 @@ protected void onCreate(Bundle savedInstanceState) {
protected void onStop() {
super.onStop();
if (!isFinishing()) {
WidgetStatus.update(this);
UIUtils.saveCollectionInBackground();
}
}
Expand Down
2 changes: 0 additions & 2 deletions AnkiDroid/src/main/java/com/ichi2/anki/NoteEditor.java
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,6 @@
import com.ichi2.utils.NamedJSONComparator;
import com.ichi2.utils.NoteFieldDecorator;
import com.ichi2.utils.TextViewUtil;
import com.ichi2.widget.WidgetStatus;

import com.ichi2.utils.JSONArray;
import com.ichi2.utils.JSONObject;
Expand Down Expand Up @@ -716,7 +715,6 @@ private void modifyCurrentSelection(Toolbar.TextFormatter formatter, FieldEditTe
protected void onStop() {
super.onStop();
if (!isFinishing()) {
WidgetStatus.update(this);
UIUtils.saveCollectionInBackground();
}
}
Expand Down
4 changes: 0 additions & 4 deletions AnkiDroid/src/main/java/com/ichi2/anki/Reviewer.java
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,6 @@
import com.ichi2.utils.Computation;
import com.ichi2.utils.Permissions;
import com.ichi2.utils.ViewGroupUtils;
import com.ichi2.widget.WidgetStatus;

import java.lang.ref.WeakReference;
import java.util.Collections;
Expand Down Expand Up @@ -1094,9 +1093,6 @@ protected void switchTopBarVisibility(int visible) {
protected void onStop() {
super.onStop();

if (!isFinishing() && colIsOpen() && mSched != null) {
WidgetStatus.update(this);
}
UIUtils.saveCollectionInBackground();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
import com.ichi2.anki.StudyOptionsFragment.StudyOptionsListener;
import com.ichi2.anki.dialogs.customstudy.CustomStudyDialog;
import com.ichi2.anki.dialogs.customstudy.CustomStudyDialogFactory;
import com.ichi2.widget.WidgetStatus;

import timber.log.Timber;

Expand Down Expand Up @@ -112,7 +111,6 @@ public void onBackPressed() {
public void onStop() {
super.onStop();
if (colIsOpen()) {
WidgetStatus.update(this);
UIUtils.saveCollectionInBackground();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import androidx.annotation.NonNull;
import timber.log.Timber;

import static android.content.Context.NOTIFICATION_SERVICE;
import static com.ichi2.anki.DeckOptions.reminderToCalendar;
import static com.ichi2.anki.Preferences.MINIMUM_CARDS_DUE_FOR_NOTIFICATION;

Expand Down Expand Up @@ -137,12 +138,14 @@ public static void scheduleNotification(Time time, Context context) {
calendar.set(Calendar.HOUR_OF_DAY, getRolloverHourOfDay(context));
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
Intent intent = new Intent(context, NotificationService.class);
intent.putExtra(NotificationService.CARD_NOTIFICATION_TYPE, NotificationService.CARD_NOTIFICATION_ALARM);
final PendingIntent notificationIntent =
CompatHelper.getCompat().getImmutableBroadcastIntent(context, 0, new Intent(context, NotificationService.class), 0);
CompatHelper.getCompat().getImmutableBroadcastIntent(context, 0, intent, 0);
alarmManager.setRepeating(
AlarmManager.RTC_WAKEUP,
calendar.getTimeInMillis(),
AlarmManager.INTERVAL_DAY,
15000,
notificationIntent
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Color;
import android.util.Log;

import androidx.core.app.NotificationCompat;
import androidx.core.content.ContextCompat;

Expand All @@ -32,6 +34,7 @@
import com.ichi2.compat.CompatHelper;
import com.ichi2.anki.DecksMetaData;

import androidx.preference.PreferenceManager;
import timber.log.Timber;

import static com.ichi2.anki.Preferences.MINIMUM_CARDS_DUE_FOR_NOTIFICATION;
Expand All @@ -41,49 +44,82 @@ public class NotificationService extends BroadcastReceiver {
/** The id of the notification for due cards. */
private static final int WIDGET_NOTIFY_ID = 1;

public static final int CARD_NOTIFICATION_WIDGET = 10;
public static final int CARD_NOTIFICATION_ALARM = 11;
public static final String CARD_NOTIFICATION_TYPE = "CARD_NOTIFICATION_TYPE";

public static final String INTENT_ACTION = "com.ichi2.anki.intent.action.SHOW_NOTIFICATION";

@Override
public void onReceive(Context context, Intent intent) {
Timber.i("NotificationService: OnStartCommand");
Log.d("AACC", "onReceive: NOTIFICATION");
NotificationManager manager = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);

SharedPreferences preferences = AnkiDroidApp.getSharedPrefs(context);
int minCardsDue = Integer.parseInt(preferences.getString(MINIMUM_CARDS_DUE_FOR_NOTIFICATION, Integer.toString(Preferences.PENDING_NOTIFICATIONS_ONLY)));
int dueCardsCount = new DecksMetaData(context).getTotalDueCards().first;
if (dueCardsCount >= minCardsDue) {
// Build basic notification
String cardsDueText = context.getResources()
.getQuantityString(R.plurals.widget_minimum_cards_due_notification_ticker_text, dueCardsCount, dueCardsCount);

// This generates a log warning "Use of stream types is deprecated..."
// The NotificationCompat code uses setSound() no matter what we do and triggers it.
NotificationCompat.Builder builder =
new NotificationCompat.Builder(context,
NotificationChannels.getId(NotificationChannels.Channel.GENERAL))
.setCategory(NotificationCompat.CATEGORY_REMINDER)
.setSmallIcon(R.drawable.ic_stat_notify)
.setColor(ContextCompat.getColor(context, R.color.material_light_blue_700))
.setContentTitle(cardsDueText)
.setTicker(cardsDueText);
// Enable vibrate and blink if set in preferences
if (preferences.getBoolean("widgetVibrate", false)) {
builder.setVibrate(new long[] { 1000, 1000, 1000});

switch (intent.getIntExtra(CARD_NOTIFICATION_TYPE, CARD_NOTIFICATION_ALARM)) {
case CARD_NOTIFICATION_WIDGET: {
// We have to show the notification always. Because we are checking the condition before sending.
Log.d("AACC", "onReceive: NOTIFICATION WIDGET");
buildNotification(context, dueCardsCount, preferences, manager);
}
if (preferences.getBoolean("widgetBlink", false)) {
builder.setLights(Color.BLUE, 1000, 1000);
break;
case CARD_NOTIFICATION_ALARM: {
Log.d("AACC", "onReceive: NOTIFICATION ALARM");
if (dueCardsCount >= minCardsDue) {
buildNotification(context, dueCardsCount, preferences, manager);
} else {
// Cancel the existing notification, if any.
cancelNotification(manager);
}
}
break;
default: {
Log.d("AACC", "onReceive: NOTIFICATION DEFAULT");
// Cancel all the pending notification.
cancelNotification(manager);
}
// Creates an explicit intent for an Activity in your app
Intent resultIntent = new Intent(context, DeckPicker.class);
resultIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
PendingIntent resultPendingIntent = CompatHelper.getCompat().getImmutableActivityIntent(context, 0, resultIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
builder.setContentIntent(resultPendingIntent);
// mId allows you to update the notification later on.
manager.notify(WIDGET_NOTIFY_ID, builder.build());
} else {
// Cancel the existing notification, if any.
manager.cancel(WIDGET_NOTIFY_ID);
}
}

private void buildNotification(Context context, int dueCardsCount, SharedPreferences preferences, NotificationManager manager) {
Log.d("AACC", "buildNotification: BUILD NOTIFICATION");
// Build basic notification
String cardsDueText = context.getResources()
.getQuantityString(R.plurals.widget_minimum_cards_due_notification_ticker_text, dueCardsCount, dueCardsCount);

// This generates a log warning "Use of stream types is deprecated..."
// The NotificationCompat code uses setSound() no matter what we do and triggers it.
NotificationCompat.Builder builder =
new NotificationCompat.Builder(context,
NotificationChannels.getId(NotificationChannels.Channel.GENERAL))
.setCategory(NotificationCompat.CATEGORY_REMINDER)
.setSmallIcon(R.drawable.ic_stat_notify)
.setColor(ContextCompat.getColor(context, R.color.material_light_blue_700))
.setContentTitle(cardsDueText)
.setTicker(cardsDueText);
// Enable vibrate and blink if set in preferences
if (preferences.getBoolean("widgetVibrate", false)) {
builder.setVibrate(new long[] { 1000, 1000, 1000});
}
if (preferences.getBoolean("widgetBlink", false)) {
builder.setLights(Color.BLUE, 1000, 1000);
}
// Creates an explicit intent for an Activity in your app
Intent resultIntent = new Intent(context, DeckPicker.class);
resultIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
PendingIntent resultPendingIntent = CompatHelper.getCompat().getImmutableActivityIntent(context, 0, resultIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
builder.setContentIntent(resultPendingIntent);
// mId allows you to update the notification later on.
manager.notify(WIDGET_NOTIFY_ID, builder.build());
}

private void cancelNotification(NotificationManager manager) {
Log.d("AACC", "cancelNotification: CANCEL NOTIFICATION");
manager.cancel(WIDGET_NOTIFY_ID);
}
}
26 changes: 23 additions & 3 deletions AnkiDroid/src/main/java/com/ichi2/widget/AnkiDroidWidgetSmall.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import android.content.res.Configuration;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import android.util.TypedValue;
import android.view.View;
import android.widget.RemoteViews;
Expand All @@ -35,8 +36,10 @@
import com.ichi2.anki.IntentHandler;
import com.ichi2.anki.R;
import com.ichi2.anki.analytics.UsageAnalytics;
import com.ichi2.anki.services.NotificationService;
import com.ichi2.compat.CompatHelper;

import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import timber.log.Timber;

public class AnkiDroidWidgetSmall extends AppWidgetProvider {
Expand All @@ -59,6 +62,7 @@ public void onEnabled(Context context) {
Timber.d("SmallWidget: Widget enabled");
SharedPreferences preferences = AnkiDroidApp.getSharedPrefs(context);
preferences.edit().putBoolean("widgetSmallEnabled", true).commit();
new WidgetAlarm().setAlarm(context.getApplicationContext());
UsageAnalytics.sendAnalyticsEvent(this.getClass().getSimpleName(), "enabled");
}

Expand All @@ -70,6 +74,7 @@ public void onDisabled(Context context) {
SharedPreferences preferences = AnkiDroidApp.getSharedPrefs(context);
preferences.edit().putBoolean("widgetSmallEnabled", false).commit();
UsageAnalytics.sendAnalyticsEvent(this.getClass().getSimpleName(), "disabled");
new WidgetAlarm().stopAlarm(context.getApplicationContext());
}

@Override
Expand Down Expand Up @@ -120,25 +125,28 @@ public static class UpdateService extends Service {


public void doUpdate(Context context) {
Log.d("AACC", "doUpdate: UPDATING WIDGET");
AppWidgetManager.getInstance(context)
.updateAppWidget(new ComponentName(context, AnkiDroidWidgetSmall.class), buildUpdate(context, true));
.updateAppWidget(new ComponentName(context, AnkiDroidWidgetSmall.class), buildUpdate(context, true, "DO UPDATE"));
}

@Override
@Deprecated
public void onStart(Intent intent, int startId) {
Timber.i("SmallWidget: OnStart");
Log.d("AACC", "onStart: ON START");

RemoteViews updateViews = buildUpdate(this, true);
RemoteViews updateViews = buildUpdate(this, true, "ON START");

ComponentName thisWidget = new ComponentName(this, AnkiDroidWidgetSmall.class);
AppWidgetManager manager = AppWidgetManager.getInstance(this);
manager.updateAppWidget(thisWidget, updateViews);
}


private RemoteViews buildUpdate(Context context, boolean updateDueDecksNow) {
private RemoteViews buildUpdate(Context context, boolean updateDueDecksNow, String update) {
Timber.d("buildUpdate");
Log.d("AACC", "buildUpdate: BUILD UPDATE --> " + update);

RemoteViews updateViews = new RemoteViews(context.getPackageName(), R.layout.widget_small);

Expand Down Expand Up @@ -188,6 +196,18 @@ public void onReceive(Context context, Intent intent) {
}
updateViews.setViewVisibility(R.id.widget_due, View.INVISIBLE);
} else {
// NOTIFICATION
SharedPreferences preferences = AnkiDroidApp.getSharedPrefs(context);
int lastUpdatedCard = preferences.getInt("widgetCard", 0);
// If their is any change in card the show the notification.
if (lastUpdatedCard != mDueCardsCount) {
Intent intent = new Intent(NotificationService.INTENT_ACTION);
Context appContext = context.getApplicationContext();
intent.putExtra(NotificationService.CARD_NOTIFICATION_TYPE, NotificationService.CARD_NOTIFICATION_WIDGET);
LocalBroadcastManager.getInstance(appContext).sendBroadcast(intent);
preferences.edit().putInt("widgetCard", mDueCardsCount).apply();
}

updateViews.setViewVisibility(R.id.ankidroid_widget_small_finish_layout, View.INVISIBLE);
updateViews.setViewVisibility(R.id.widget_due, View.VISIBLE);
updateViews.setTextViewText(R.id.widget_due, Integer.toString(mDueCardsCount));
Expand Down
Loading

0 comments on commit 9f38230

Please sign in to comment.