mirror of
https://github.com/streetwriters/notesnook.git
synced 2026-09-02 04:01:43 +02:00
mobile: fix widgets do not refresh after app data is cleared, require a restart.
This commit is contained in:
@@ -193,6 +193,16 @@ public class RCTNNativeModule extends ReactContextBaseJavaModule {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Redraws every widget from scratch. Needed because the app can be stopped while its widgets
|
||||
* stay on the home screen: clearing app data empties the store without the widgets ever being
|
||||
* told, so they keep showing content that is gone until something forces a redraw.
|
||||
*/
|
||||
@ReactMethod
|
||||
public void refreshWidgets() {
|
||||
WidgetUtils.refreshAll(mContext);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void updateReminderWidget() {
|
||||
AppWidgetManager wm = AppWidgetManager.getInstance(mContext);
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package com.streetwriters.notesnook;
|
||||
|
||||
import android.app.ActivityOptions;
|
||||
import android.appwidget.AppWidgetManager;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
@@ -18,9 +20,11 @@ import com.streetwriters.notesnook.datatypes.Reminder;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Shared helpers for the home screen widgets.
|
||||
@@ -36,6 +40,56 @@ public class WidgetUtils {
|
||||
*/
|
||||
private static final int MAX_REMINDERS = 50;
|
||||
|
||||
/**
|
||||
* Redraws every widget that currently exists, and drops stored notes for widgets that no
|
||||
* longer do.
|
||||
*
|
||||
* Everything else keys off what we have stored, which is fine while the app is running but
|
||||
* leaves widgets showing content that no longer exists once the store is emptied underneath
|
||||
* them (clearing app data) or a widget is removed while the app is stopped (onDeleted never
|
||||
* arrives). Starting from the widgets the system knows about, rather than from our own data,
|
||||
* is what makes this self-correcting.
|
||||
*
|
||||
* NoteWidget is left alone deliberately: it is a static button with no stored state, and its
|
||||
* layout depends on the size it was last given.
|
||||
*/
|
||||
static void refreshAll(Context context) {
|
||||
AppWidgetManager manager = AppWidgetManager.getInstance(context);
|
||||
|
||||
int[] noteWidgetIds = manager.getAppWidgetIds(
|
||||
new ComponentName(context, NotePreviewWidget.class));
|
||||
removeOrphanedNotes(context, noteWidgetIds);
|
||||
for (int appWidgetId : noteWidgetIds) {
|
||||
NotePreviewWidget.updateAppWidget(context, manager, appWidgetId);
|
||||
}
|
||||
|
||||
for (int appWidgetId : manager.getAppWidgetIds(
|
||||
new ComponentName(context, ReminderWidgetProvider.class))) {
|
||||
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_reminders);
|
||||
ReminderWidgetProvider.updateAppWidget(context, manager, appWidgetId, views);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Drops stored notes whose widget is gone, so the preferences file cannot grow forever.
|
||||
*/
|
||||
private static void removeOrphanedNotes(Context context, int[] liveWidgetIds) {
|
||||
Set<String> live = new HashSet<>();
|
||||
for (int appWidgetId : liveWidgetIds) live.add(String.valueOf(appWidgetId));
|
||||
|
||||
SharedPreferences preferences = context.getSharedPreferences(PREFERENCES, Context.MODE_PRIVATE);
|
||||
SharedPreferences.Editor edit = preferences.edit();
|
||||
boolean changed = false;
|
||||
|
||||
for (String key : preferences.getAll().keySet()) {
|
||||
// Leave anything that is not a widget id alone, the reminders list included.
|
||||
if (parseWidgetId(key) == null || live.contains(key)) continue;
|
||||
edit.remove(key);
|
||||
changed = true;
|
||||
}
|
||||
if (changed) edit.apply();
|
||||
}
|
||||
|
||||
/**
|
||||
* The note each note widget is showing, keyed by widget id.
|
||||
*
|
||||
|
||||
@@ -81,6 +81,7 @@ import {
|
||||
setUpdateAvailableMessage
|
||||
} from "../services/message";
|
||||
import Navigation from "../services/navigation";
|
||||
import { NotePreviewWidget } from "../services/note-preview-widget";
|
||||
import Notifications from "../services/notifications";
|
||||
import PremiumService from "../services/premium";
|
||||
import SettingsService from "../services/settings";
|
||||
@@ -574,6 +575,11 @@ export const useAppEvents = () => {
|
||||
useEffect(() => {
|
||||
if (isAppLoading) return;
|
||||
|
||||
// Widgets outlive the app process, so they can be left showing content the app no longer has
|
||||
// (most obviously after the user clears app data). Nothing can run at that moment, so the
|
||||
// first launch afterwards is the earliest chance to put them right.
|
||||
NotePreviewWidget.updateNotes();
|
||||
|
||||
let subscriptions: EventManagerSubscription[] = [];
|
||||
const eventManager = db.eventManager;
|
||||
subscriptions = [
|
||||
|
||||
@@ -34,6 +34,10 @@ export const NotePreviewWidget = {
|
||||
|
||||
NotesnookModule.updateWidgetNote(id, JSON.stringify(newNote));
|
||||
}
|
||||
// Redraw from the widgets that actually exist rather than only the ones we
|
||||
// have notes for. After app data is cleared there are none, and the widgets
|
||||
// would otherwise keep showing content that no longer exists.
|
||||
NotesnookModule.refreshWidgets();
|
||||
}, 500);
|
||||
},
|
||||
updateNote: async (id: string, note: Note) => {
|
||||
|
||||
@@ -45,6 +45,7 @@ interface NotesnookModuleInterface {
|
||||
hasWidgetNote: (noteId: string) => Promise<boolean>;
|
||||
updateWidgetNote: (noteId: string, data: string) => void;
|
||||
updateReminderWidget: () => void;
|
||||
refreshWidgets: () => void;
|
||||
isGestureNavigationEnabled: () => boolean;
|
||||
addShortcut: (
|
||||
id: string,
|
||||
@@ -81,6 +82,7 @@ export const NotesnookModule: NotesnookModuleInterface = Platform.select({
|
||||
hasWidgetNote: () => {},
|
||||
updateWidgetNote: () => {},
|
||||
updateReminderWidget: () => {},
|
||||
refreshWidgets: () => {},
|
||||
isGestureNavigationEnabled: () => true,
|
||||
addShortcut: () => Promise.resolve(false),
|
||||
removeShortcut: () => Promise.resolve(false),
|
||||
|
||||
Reference in New Issue
Block a user