@@ -26,12 +26,13 @@ import android.view.View
26
26
import android.widget.RemoteViews
27
27
import com.ichi2.anki.AnkiDroidApp
28
28
import com.ichi2.anki.CrashReportService
29
- import com.ichi2.anki.DeckUtils
30
29
import com.ichi2.anki.R
31
30
import com.ichi2.anki.Reviewer
32
31
import com.ichi2.anki.analytics.UsageAnalytics
32
+ import com.ichi2.anki.isCollectionEmpty
33
33
import com.ichi2.anki.pages.DeckOptions
34
34
import com.ichi2.libanki.DeckId
35
+ import com.ichi2.libanki.Decks.Companion.NOT_FOUND_DECK_ID
35
36
import com.ichi2.widget.ACTION_UPDATE_WIDGET
36
37
import com.ichi2.widget.AnalyticsWidgetProvider
37
38
import com.ichi2.widget.cancelRecurringAlarm
@@ -60,43 +61,53 @@ class CardAnalysisWidget : AnalyticsWidgetProvider() {
60
61
* Updates the widget with the deck data.
61
62
*
62
63
* This method updates the widget view content with the deck data corresponding
63
- * to the provided deck ID. If the deck is deleted, the widget will be cleared .
64
+ * to the provided deck ID. If the deck is deleted, the widget will be show a message "Missing deck. Please reconfigure" .
64
65
*
65
66
* @param context the context of the application
66
67
* @param appWidgetManager the AppWidgetManager instance
67
68
* @param appWidgetId the ID of the app widget
68
- * @param deckId the ID of the deck to be displayed in the widget.
69
69
*/
70
70
fun updateWidget (
71
71
context : Context ,
72
72
appWidgetManager : AppWidgetManager ,
73
- appWidgetId : Int ,
74
- deckId : DeckId ?
73
+ appWidgetId : Int
75
74
) {
75
+ val deckId = getDeckIdForWidget(context, appWidgetId)
76
76
val remoteViews = RemoteViews (context.packageName, R .layout.widget_card_analysis)
77
- if (deckId == null ) {
77
+
78
+ if (deckId == NOT_FOUND_DECK_ID ) {
79
+ // If deckId is null, it means no deck was selected or the selected deck was deleted.
80
+ // In this case, we don't save the null value to preferences because we want to
81
+ // keep the previous deck ID if the user reconfigures the widget later.
82
+ // Instead, we show a message prompting the user to reconfigure the widget.
78
83
showMissingDeck(context, appWidgetManager, appWidgetId, remoteViews)
79
84
return
80
85
}
86
+
81
87
AnkiDroidApp .applicationScope.launch {
82
- val isCollectionEmpty = DeckUtils . isCollectionEmpty()
88
+ val isCollectionEmpty = isCollectionEmpty()
83
89
if (isCollectionEmpty) {
84
90
showCollectionDeck(context, appWidgetManager, appWidgetId, remoteViews)
85
91
return @launch
86
92
}
87
93
88
94
val deckData = getDeckNameAndStats(deckId)
89
-
90
95
if (deckData == null ) {
91
- // If the deck was deleted, clear the stored deck ID
92
- CardAnalysisWidgetPreferences (context).saveSelectedDeck(appWidgetId, null )
96
+ // The deck was found but no data could be fetched, so update the preferences to remove the deck.
97
+ // This ensures that the widget does not retain a reference to a non-existent or invalid deck.
98
+ CardAnalysisWidgetPreferences (context).saveSelectedDeck(appWidgetId, NOT_FOUND_DECK_ID )
93
99
showMissingDeck(context, appWidgetManager, appWidgetId, remoteViews)
94
100
return @launch
95
101
}
96
102
showDeck(context, appWidgetManager, appWidgetId, remoteViews, deckData)
97
103
}
98
104
}
99
105
106
+ private fun getDeckIdForWidget (context : Context , appWidgetId : Int ): DeckId {
107
+ val widgetPreferences = CardAnalysisWidgetPreferences (context)
108
+ return widgetPreferences.getSelectedDeckIdFromPreferences(appWidgetId) ? : NOT_FOUND_DECK_ID
109
+ }
110
+
100
111
private fun showCollectionDeck (
101
112
context : Context ,
102
113
appWidgetManager : AppWidgetManager ,
@@ -160,6 +171,7 @@ class CardAnalysisWidget : AnalyticsWidgetProvider() {
160
171
Intent (context, Reviewer ::class .java).apply {
161
172
action = Intent .ACTION_VIEW
162
173
putExtra(" deckId" , deckData.deckId)
174
+ addFlags(Intent .FLAG_ACTIVITY_CLEAR_TOP )
163
175
}
164
176
} else {
165
177
DeckOptions .getIntent(context, deckData.deckId)
@@ -189,9 +201,8 @@ class CardAnalysisWidget : AnalyticsWidgetProvider() {
189
201
Timber .d(" AppWidgetIds to update: ${appWidgetIds.joinToString(" , " )} " )
190
202
191
203
for (appWidgetId in appWidgetIds) {
192
- val widgetPreferences = CardAnalysisWidgetPreferences (context)
193
- val deckId = widgetPreferences.getSelectedDeckIdFromPreferences(appWidgetId)
194
- updateWidget(context, appWidgetManager, appWidgetId, deckId)
204
+ getDeckIdForWidget(context, appWidgetId)
205
+ updateWidget(context, appWidgetManager, appWidgetId)
195
206
}
196
207
}
197
208
}
@@ -204,21 +215,25 @@ class CardAnalysisWidget : AnalyticsWidgetProvider() {
204
215
) {
205
216
Timber .d(" Performing widget update for appWidgetIds: %s" , appWidgetIds)
206
217
207
- val widgetPreferences = CardAnalysisWidgetPreferences (context)
208
-
209
218
for (widgetId in appWidgetIds) {
210
219
Timber .d(" Updating widget with ID: $widgetId " )
211
- val selectedDeckId = widgetPreferences.getSelectedDeckIdFromPreferences(widgetId)
212
220
213
- /* *Explanation of behavior when selectedDeckId is empty
221
+ // Get the selected deck ID internally
222
+ val selectedDeckId = getDeckIdForWidget(context, widgetId)
223
+
224
+ /* *
225
+ * Explanation of behavior when selectedDeckId is empty
214
226
* If selectedDeckId is empty, the widget will retain the previous deck.
215
227
* This behavior ensures that the widget does not display an empty view, which could be
216
228
* confusing to the user. Instead, it maintains the last known state until a new valid
217
229
* deck ID is provided. This approach prioritizes providing a consistent
218
230
* user experience over showing an empty or default state.
219
231
*/
220
232
Timber .d(" Selected deck ID: $selectedDeckId for widget ID: $widgetId " )
221
- updateWidget(context, appWidgetManager, widgetId, selectedDeckId)
233
+
234
+ // Update the widget with the selected deck ID
235
+ updateWidget(context, appWidgetManager, widgetId)
236
+ // Set the recurring alarm for the widget
222
237
setRecurringAlarm(context, widgetId, CardAnalysisWidget ::class .java)
223
238
}
224
239
@@ -244,19 +259,23 @@ class CardAnalysisWidget : AnalyticsWidgetProvider() {
244
259
245
260
Timber .d(" Received ACTION_APPWIDGET_UPDATE with widget ID: $appWidgetId and selectedDeckId: $selectedDeckId " )
246
261
247
- if (appWidgetId != AppWidgetManager .INVALID_APPWIDGET_ID && selectedDeckId != - 1L ) {
262
+ if (appWidgetId != AppWidgetManager .INVALID_APPWIDGET_ID ) {
248
263
Timber .d(" Updating widget with ID: $appWidgetId " )
249
- // Wrap selectedDeckId into a LongArray
250
- updateWidget(context, appWidgetManager, appWidgetId, selectedDeckId)
264
+
265
+ // Update the widget using the internally fetched deck ID
266
+ updateWidget(context, appWidgetManager, appWidgetId)
267
+
251
268
Timber .d(" Widget update process completed for widget ID: $appWidgetId " )
252
269
}
253
270
}
254
- // This custom action is received to update a specific widget.
255
- // It is triggered by the setRecurringAlarm method to refresh the widget's data periodically.
271
+ // Custom action to update a specific widget, triggered by the setRecurringAlarm method
256
272
ACTION_UPDATE_WIDGET -> {
257
273
val appWidgetId = intent.getIntExtra(AppWidgetManager .EXTRA_APPWIDGET_ID , AppWidgetManager .INVALID_APPWIDGET_ID )
258
274
if (appWidgetId != AppWidgetManager .INVALID_APPWIDGET_ID ) {
259
275
Timber .d(" Received ACTION_UPDATE_WIDGET for widget ID: $appWidgetId " )
276
+
277
+ // Update the widget using the internally fetched deck ID
278
+ updateWidget(context, AppWidgetManager .getInstance(context), appWidgetId)
260
279
}
261
280
}
262
281
AppWidgetManager .ACTION_APPWIDGET_DELETED -> {
0 commit comments