Anki-Android icon indicating copy to clipboard operation
Anki-Android copied to clipboard

[GSoC'24] Card Analysis Widget .

Open xenonnn4w opened this issue 1 year ago • 1 comments

Purpose / Description

This commit introduces the Card Analysis Widget, which displays a deck name along with the number of cards that are new, in learning, and due for review.

Approach

On the same pattern as Deck Picker Widget.

How Has This Been Tested?

image

https://github.com/user-attachments/assets/38e138d2-6c34-42a2-a675-85f18e683be7

Checklist

Please, go through these checks before submitting the PR.

  • [x] You have a descriptive commit message with a short title (first line, max 50 chars).
  • [x] You have commented your code, particularly in hard-to-understand areas
  • [x] You have performed a self-review of your own code
  • [x] UI changes: include screenshots of all affected screens (in particular showing any new or changed strings)
  • [ ] UI Changes: You have tested your change using the Google Accessibility Scanner

xenonnn4w avatar Aug 27 '24 22:08 xenonnn4w

Message to maintainers, this PR contains strings changes.

  1. Before merging this PR, it is best to run the "Sync Translations" GitHub action, then make and merge a PR from the i18n_sync branch to get translations cleaned out.
  2. Then merge this PR, and immediately do another translation PR so the huge change made by this PR's key changes are all by themselves.

Read more about updating strings on the wiki,

github-actions[bot] avatar Aug 27 '24 22:08 github-actions[bot]

I get a "You may only select one deck" after selecting the only deck. I'd prefer if you could open the deck selector as soon as configuration is opened. There is really no reason to have the use press "+". Similarly, once the selection is done, you can directly save it. In the worst case, if the user want to change the deck they can reconfigure it

Arthur-Milchior avatar Aug 30 '24 02:08 Arthur-Milchior

If the deck is deleted, I'd prefer if you could either delete the widget alltogether if it's possible (@david-allison do you agree?) or at least show a message stating something such as "Missing deck. Please reconfigure" and tapping on the widget would open the configuration view instead of opening ankidroid

Arthur-Milchior avatar Aug 30 '24 02:08 Arthur-Milchior

Deleting the widget: it doesn't seem wise. Renaming a deck would count as a deletion, whereas the user would expect a reconfiguration

david-allison avatar Aug 30 '24 06:08 david-allison

I'm fine with not deleting it. But at least, we should not leave it empty

Arthur-Milchior avatar Aug 30 '24 11:08 Arthur-Milchior

I'm happy, and to be frank, pleasantly surprised, you were able to update so quickly.

A few requests:

  • you shouldn't be able to close the list of decks except by selecting a deck. Closing the list, e.g. with "esc" should close the whole configuration.
  • Remove the + symbol. It won't be used.
  • If the collection is empty instead of "missing deck", reuse the "not initialized" string. And don't open the configuration, as it close automatically.
  • Check whether there is a way to have the deck list take more of the screen, given that the part below the deck list is of no interest

Arthur-Milchior avatar Aug 30 '24 21:08 Arthur-Milchior

To save you time, here are the typing change I created while reviewing and testing your code

Subject: [PATCH] Notify the UI that a sync was done

In this case, I really don't think it's realistic to expect an
OpChange from the backend. The backend already sends informations that
are relevant for the sync process. Given that "sync" does not uses the
processes uses for undoable change (indeed, it should not be
undoable), no OpChange is generated.

It seems reasonable in this place at least to directly notify the
observers.

Given that the observers expect an OpChanges, I create one, and simply
assume everything may be changed. This seems reasonable in case of
sync, and it's sufficiently rare that the cost won't be prohibitive
anyway.

Fixed: #16943
Fixed: #16942
---
Index: AnkiDroid/src/test/java/com/ichi2/anki/widget/deckpicker/DeckNameAndStatsTest.kt
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/AnkiDroid/src/test/java/com/ichi2/anki/widget/deckpicker/DeckNameAndStatsTest.kt b/AnkiDroid/src/test/java/com/ichi2/anki/widget/deckpicker/DeckNameAndStatsTest.kt
--- a/AnkiDroid/src/test/java/com/ichi2/anki/widget/deckpicker/DeckNameAndStatsTest.kt	(revision a4a4c1bba2a4efeb201212bc201724b9d7ac6c8d)
+++ b/AnkiDroid/src/test/java/com/ichi2/anki/widget/deckpicker/DeckNameAndStatsTest.kt	(date 1725056072761)
@@ -18,7 +18,7 @@
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import com.ichi2.anki.RobolectricTest
-import com.ichi2.widget.deckpicker.getDeckNameAndStats
+import com.ichi2.widget.deckpicker.getDeckNamesAndStats
 import org.junit.Test
 import org.junit.runner.RunWith
 import kotlin.test.assertEquals
@@ -32,7 +32,7 @@
         val deck2Id = addDeck("Deck 2")
         val deckIds = listOf(deck1Id, deck2Id)
 
-        val result = getDeckNameAndStats(deckIds)
+        val result = getDeckNamesAndStats(deckIds)
 
         assertEquals(2, result.size)
         assertEquals("Deck 1", result[0].name)
@@ -48,7 +48,7 @@
         val deckCId = addDeck("Deck C")
         val deckIds = listOf(deckCId, deckAId, deckBId)
 
-        val result = getDeckNameAndStats(deckIds)
+        val result = getDeckNamesAndStats(deckIds)
 
         assertEquals(3, result.size)
         assertEquals("Deck C", result[0].name)
@@ -65,7 +65,7 @@
         val child1Id = addDeck("Deck 1::Child 1")
         val deckIds = listOf(deck1Id, child1Id)
 
-        val result = getDeckNameAndStats(deckIds)
+        val result = getDeckNamesAndStats(deckIds)
 
         assertEquals(2, result.size)
         assertEquals("Deck 1", result[0].name)
Index: AnkiDroid/src/main/java/com/ichi2/widget/cardanalysis/CardAnalysisWidgetConfig.kt
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/AnkiDroid/src/main/java/com/ichi2/widget/cardanalysis/CardAnalysisWidgetConfig.kt b/AnkiDroid/src/main/java/com/ichi2/widget/cardanalysis/CardAnalysisWidgetConfig.kt
--- a/AnkiDroid/src/main/java/com/ichi2/widget/cardanalysis/CardAnalysisWidgetConfig.kt	(revision a4a4c1bba2a4efeb201212bc201724b9d7ac6c8d)
+++ b/AnkiDroid/src/main/java/com/ichi2/widget/cardanalysis/CardAnalysisWidgetConfig.kt	(date 1725056710433)
@@ -104,8 +104,8 @@
 
             initializeUIComponents()
             // Show the Deck selection dialog only when there are no decks selected while opening the configuration screen.
-            val selectedDeckIds = cardAnalysisWidgetPreferences.getSelectedDeckIdFromPreferences(appWidgetId)
-            if (selectedDeckIds.isEmpty()) {
+            val selectedDeckId = cardAnalysisWidgetPreferences.getSelectedDeckIdFromPreferences(appWidgetId)
+            if (selectedDeckId == null) {
                 showDeckSelectionDialog()
             }
         }
@@ -220,16 +220,14 @@
 
     /** Updates the view according to the saved preference for appWidgetId.*/
     fun updateViewWithSavedPreferences() {
-        val selectedDeckIds = cardAnalysisWidgetPreferences.getSelectedDeckIdFromPreferences(appWidgetId)
-        if (selectedDeckIds.isNotEmpty()) {
+        val selectedDeckId = cardAnalysisWidgetPreferences.getSelectedDeckIdFromPreferences(appWidgetId)?: return
             lifecycleScope.launch {
                 val decks = fetchDecks()
-                val selectedDecks = decks.filter { it.deckId in selectedDeckIds }
+                val selectedDecks = decks.filter { it.deckId == selectedDeckId }
                 selectedDecks.forEach { deckAdapter.addDeck(it) }
                 updateViewVisibility()
                 updateFabVisibility()
             }
-        }
     }
 
     /** Asynchronously displays the list of deck in the selection dialog. */
@@ -287,9 +285,9 @@
             hasUnsavedChanges = false
             setUnsavedChanges(false)
 
-            val selectedDeckIds = cardAnalysisWidgetPreferences.getSelectedDeckIdFromPreferences(appWidgetId)
+            val selectedDeckId = cardAnalysisWidgetPreferences.getSelectedDeckIdFromPreferences(appWidgetId)
             val appWidgetManager = AppWidgetManager.getInstance(this)
-            CardAnalysisWidget.updateWidget(this, appWidgetManager, appWidgetId, selectedDeckIds)
+            CardAnalysisWidget.updateWidget(this, appWidgetManager, appWidgetId, selectedDeckId)
 
             val resultValue = Intent().putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId)
             setResult(RESULT_OK, resultValue)
@@ -310,14 +308,14 @@
     }
 
     fun saveSelectedDecksToPreferencesCardAnalysisWidget() {
-        val selectedDecks = deckAdapter.deckIds.map { it }
-        cardAnalysisWidgetPreferences.saveSelectedDeck(appWidgetId, selectedDecks.map { it.toString() })
+        val selectedDeck = deckAdapter.deckIds.getOrNull(0)
+        cardAnalysisWidgetPreferences.saveSelectedDeck(appWidgetId, selectedDeck)
 
         val updateIntent = Intent(this, CardAnalysisWidget::class.java).apply {
             action = AppWidgetManager.ACTION_APPWIDGET_UPDATE
             putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, intArrayOf(appWidgetId))
 
-            putExtra("card_analysis_widget_selected_deck_ids", selectedDecks.toList().toLongArray())
+            putExtra("card_analysis_widget_selected_deck_ids", selectedDeck)
         }
 
         sendBroadcast(updateIntent)
Index: AnkiDroid/src/test/java/com/ichi2/anki/widget/cardanalysis/CardAnalysisWidgetConfigTest.kt
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/AnkiDroid/src/test/java/com/ichi2/anki/widget/cardanalysis/CardAnalysisWidgetConfigTest.kt b/AnkiDroid/src/test/java/com/ichi2/anki/widget/cardanalysis/CardAnalysisWidgetConfigTest.kt
--- a/AnkiDroid/src/test/java/com/ichi2/anki/widget/cardanalysis/CardAnalysisWidgetConfigTest.kt	(revision a4a4c1bba2a4efeb201212bc201724b9d7ac6c8d)
+++ b/AnkiDroid/src/test/java/com/ichi2/anki/widget/cardanalysis/CardAnalysisWidgetConfigTest.kt	(date 1725056072761)
@@ -82,7 +82,7 @@
         activity.saveSelectedDecksToPreferencesCardAnalysisWidget()
 
         // Verify saved decks
-        val selectedDeckIds = widgetPreferences.getSelectedDeckIdFromPreferences(1).toList()
+        val selectedDeckIds = widgetPreferences.getSelectedDeckIdsFromPreferences(1).toList()
         assertThat(selectedDeckIds.contains(deck1.deckId), equalTo(true))
     }
 
@@ -96,7 +96,7 @@
     fun testLoadSavedPreferences() {
         // Save decks to preferences
         val deckIds = listOf(1L)
-        widgetPreferences.saveSelectedDeck(1, deckIds.map { it.toString() })
+        widgetPreferences.saveSelectedDecks(1, deckIds.map { it.toString() })
 
         // Load preferences
         activity.updateViewWithSavedPreferences()
Index: AnkiDroid/src/main/java/com/ichi2/widget/cardanalysis/CardAnalysisWidget.kt
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/AnkiDroid/src/main/java/com/ichi2/widget/cardanalysis/CardAnalysisWidget.kt b/AnkiDroid/src/main/java/com/ichi2/widget/cardanalysis/CardAnalysisWidget.kt
--- a/AnkiDroid/src/main/java/com/ichi2/widget/cardanalysis/CardAnalysisWidget.kt	(revision a4a4c1bba2a4efeb201212bc201724b9d7ac6c8d)
+++ b/AnkiDroid/src/main/java/com/ichi2/widget/cardanalysis/CardAnalysisWidget.kt	(date 1725056072761)
@@ -30,9 +30,11 @@
 import com.ichi2.anki.Reviewer
 import com.ichi2.anki.analytics.UsageAnalytics
 import com.ichi2.anki.pages.DeckOptions
+import com.ichi2.libanki.DeckId
 import com.ichi2.widget.ACTION_UPDATE_WIDGET
 import com.ichi2.widget.AnalyticsWidgetProvider
 import com.ichi2.widget.cancelRecurringAlarm
+import com.ichi2.widget.deckpicker.DeckWidgetData
 import com.ichi2.widget.deckpicker.getDeckNameAndStats
 import com.ichi2.widget.setRecurringAlarm
 import kotlinx.coroutines.launch
@@ -68,72 +70,85 @@
             context: Context,
             appWidgetManager: AppWidgetManager,
             appWidgetId: Int,
-            deckId: LongArray
+            deckId: DeckId?
         ) {
             val remoteViews = RemoteViews(context.packageName, R.layout.widget_card_analysis)
-
+            if (deckId == null) {
+                showMissingDeck(context, appWidgetManager, appWidgetId, remoteViews)
+                return
+            }
             AnkiDroidApp.applicationScope.launch {
-                val deckData = getDeckNameAndStats(deckId.toList())
+                val deckData = getDeckNameAndStats(deckId)
 
-                if (deckData.isEmpty()) {
+
+                if (deckData ==null) {
                     // If the deck was deleted, clear the stored deck ID
-                    val widgetPreferences = CardAnalysisWidgetPreferences(context)
-                    val selectedDeck = longArrayOf().map { it.toString() }
-                    widgetPreferences.saveSelectedDeck(appWidgetId, selectedDeck)
+                    CardAnalysisWidgetPreferences(context).saveSelectedDeck(appWidgetId, null)
+                    showMissingDeck(context, appWidgetManager, appWidgetId, remoteViews)
+                    return@launch
+                }
+                showDeck(context, appWidgetManager, appWidgetId, remoteViews, deckData)
+            }
+        }
+
+        private fun showMissingDeck(context: Context,
+                                    appWidgetManager: AppWidgetManager,
+                                    appWidgetId: Int, remoteViews: RemoteViews) {
 
-                    // Show empty_widget and set click listener to open configuration
-                    remoteViews.setViewVisibility(R.id.empty_widget, View.VISIBLE)
-                    remoteViews.setViewVisibility(R.id.cardAnalysisDataHolder, View.GONE)
-                    remoteViews.setViewVisibility(R.id.deckNameCardAnalysis, View.GONE)
+            // Show empty_widget and set click listener to open configuration
+            remoteViews.setViewVisibility(R.id.empty_widget, View.VISIBLE)
+            remoteViews.setViewVisibility(R.id.cardAnalysisDataHolder, View.GONE)
+            remoteViews.setViewVisibility(R.id.deckNameCardAnalysis, View.GONE)
 
-                    val configIntent = Intent(context, CardAnalysisWidgetConfig::class.java).apply {
-                        putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId)
-                        flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
-                    }
-                    val configPendingIntent = PendingIntent.getActivity(
-                        context,
-                        appWidgetId,
-                        configIntent,
-                        PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
-                    )
-                    remoteViews.setOnClickPendingIntent(R.id.empty_widget, configPendingIntent)
+            val configIntent = Intent(context, CardAnalysisWidgetConfig::class.java).apply {
+                putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId)
+                flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
+            }
+            val configPendingIntent = PendingIntent.getActivity(
+                context,
+                appWidgetId,
+                configIntent,
+                PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
+            )
+            remoteViews.setOnClickPendingIntent(R.id.empty_widget, configPendingIntent)
 
-                    appWidgetManager.updateAppWidget(appWidgetId, remoteViews)
-                    return@launch
-                }
+            appWidgetManager.updateAppWidget(appWidgetId, remoteViews)
+        }
 
-                val deck = deckData[0]
-                remoteViews.setTextViewText(R.id.deckNameCardAnalysis, deck.name)
-                remoteViews.setTextViewText(R.id.deckNew_card_analysis_widget, deck.newCount.toString())
-                remoteViews.setTextViewText(R.id.deckDue_card_analysis_widget, deck.reviewCount.toString())
-                remoteViews.setTextViewText(R.id.deckLearn_card_analysis_widget, deck.learnCount.toString())
+        private fun showDeck(context: Context,
+                             appWidgetManager: AppWidgetManager,
+                             appWidgetId: Int, remoteViews: RemoteViews, deckData: DeckWidgetData) {
+            remoteViews.setTextViewText(R.id.deckNameCardAnalysis, deckData.name)
+            remoteViews.setTextViewText(R.id.deckNew_card_analysis_widget, deckData.newCount.toString())
+            remoteViews.setTextViewText(R.id.deckDue_card_analysis_widget, deckData.reviewCount.toString())
+            remoteViews.setTextViewText(R.id.deckLearn_card_analysis_widget, deckData.learnCount.toString())
 
-                // Hide empty_widget and show the actual widget content
-                remoteViews.setViewVisibility(R.id.empty_widget, View.GONE)
-                remoteViews.setViewVisibility(R.id.cardAnalysisDataHolder, View.VISIBLE)
-                remoteViews.setViewVisibility(R.id.deckNameCardAnalysis, View.VISIBLE)
+            // Hide empty_widget and show the actual widget content
+            remoteViews.setViewVisibility(R.id.empty_widget, View.GONE)
+            remoteViews.setViewVisibility(R.id.cardAnalysisDataHolder, View.VISIBLE)
+            remoteViews.setViewVisibility(R.id.deckNameCardAnalysis, View.VISIBLE)
 
-                val isEmptyDeck = deck.newCount == 0 && deck.reviewCount == 0 && deck.learnCount == 0
+            val isEmptyDeck = deckData.newCount == 0 && deckData.reviewCount == 0 && deckData.learnCount == 0
 
-                val intent = if (!isEmptyDeck) {
-                    Intent(context, Reviewer::class.java).apply {
-                        action = Intent.ACTION_VIEW
-                        putExtra("deckId", deck.deckId)
-                    }
-                } else {
-                    DeckOptions.getIntent(context, deck.deckId)
-                }
-                val pendingIntent = PendingIntent.getActivity(
-                    context,
-                    deck.deckId.toInt(),
-                    intent,
-                    PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
-                )
-                remoteViews.setOnClickPendingIntent(R.id.deckNameCardAnalysis, pendingIntent)
+            val intent = if (!isEmptyDeck) {
+                Intent(context, Reviewer::class.java).apply {
+                    action = Intent.ACTION_VIEW
+                    putExtra("deckId", deckData.deckId)
+                }
+            } else {
+                DeckOptions.getIntent(context, deckData.deckId)
+            }
+            val pendingIntent = PendingIntent.getActivity(
+                context,
+                deckData.deckId.toInt(),
+                intent,
+                PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
+            )
+            remoteViews.setOnClickPendingIntent(R.id.deckNameCardAnalysis, pendingIntent)
 
-                appWidgetManager.updateAppWidget(appWidgetId, remoteViews)
-            }
+            appWidgetManager.updateAppWidget(appWidgetId, remoteViews)
         }
+
 
         /**
          * Updates the Card Analysis Widgets based on the current state of the application.
@@ -207,7 +222,7 @@
                 if (appWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID && selectedDeckId != -1L) {
                     Timber.d("Updating widget with ID: $appWidgetId")
                     // Wrap selectedDeckId into a LongArray
-                    updateWidget(context, appWidgetManager, appWidgetId, longArrayOf(selectedDeckId))
+                    updateWidget(context, appWidgetManager, appWidgetId, selectedDeckId)
                     Timber.d("Widget update process completed for widget ID: $appWidgetId")
                 }
             }
Index: AnkiDroid/src/main/java/com/ichi2/widget/cardanalysis/CardAnalysisWidgetPreferences.kt
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/AnkiDroid/src/main/java/com/ichi2/widget/cardanalysis/CardAnalysisWidgetPreferences.kt b/AnkiDroid/src/main/java/com/ichi2/widget/cardanalysis/CardAnalysisWidgetPreferences.kt
--- a/AnkiDroid/src/main/java/com/ichi2/widget/cardanalysis/CardAnalysisWidgetPreferences.kt	(revision a4a4c1bba2a4efeb201212bc201724b9d7ac6c8d)
+++ b/AnkiDroid/src/main/java/com/ichi2/widget/cardanalysis/CardAnalysisWidgetPreferences.kt	(date 1725056072761)
@@ -18,6 +18,8 @@
 
 import android.content.Context
 import androidx.core.content.edit
+import com.ichi2.libanki.DeckId
+import com.ichi2.libanki.Decks.Companion.NOT_FOUND_DECK_ID
 
 class CardAnalysisWidgetPreferences(context: Context) {
 
@@ -39,21 +41,17 @@
         }
     }
 
-    fun getSelectedDeckIdFromPreferences(appWidgetId: Int): LongArray {
-        val selectedDeckString = cardAnalysisWidgetSharedPreferences.getString(
+    fun getSelectedDeckIdFromPreferences(appWidgetId: Int): DeckId? {
+        val selectedDeckString = cardAnalysisWidgetSharedPreferences.getLong(
             getCardAnalysisExtraWidgetKey(appWidgetId),
-            ""
+            NOT_FOUND_DECK_ID
         )
-        return if (!selectedDeckString.isNullOrEmpty()) {
-            selectedDeckString.split(",").map { it.toLong() }.toLongArray()
-        } else {
-            longArrayOf()
-        }
+        return selectedDeckString.takeIf { it != NOT_FOUND_DECK_ID }
     }
 
-    fun saveSelectedDeck(appWidgetId: Int, selectedDeck: List<String>) {
+    fun saveSelectedDeck(appWidgetId: Int, selectedDeck: DeckId?) {
         cardAnalysisWidgetSharedPreferences.edit {
-            putString(getCardAnalysisExtraWidgetKey(appWidgetId), selectedDeck.joinToString(","))
+            putLong(getCardAnalysisExtraWidgetKey(appWidgetId), selectedDeck ?: NOT_FOUND_DECK_ID)
         }
     }
 }
Index: AnkiDroid/src/main/java/com/ichi2/widget/deckpicker/DeckPickerWidget.kt
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/AnkiDroid/src/main/java/com/ichi2/widget/deckpicker/DeckPickerWidget.kt b/AnkiDroid/src/main/java/com/ichi2/widget/deckpicker/DeckPickerWidget.kt
--- a/AnkiDroid/src/main/java/com/ichi2/widget/deckpicker/DeckPickerWidget.kt	(revision a4a4c1bba2a4efeb201212bc201724b9d7ac6c8d)
+++ b/AnkiDroid/src/main/java/com/ichi2/widget/deckpicker/DeckPickerWidget.kt	(date 1725056072761)
@@ -30,6 +30,7 @@
 import com.ichi2.anki.Reviewer
 import com.ichi2.anki.analytics.UsageAnalytics
 import com.ichi2.anki.pages.DeckOptions
+import com.ichi2.libanki.DeckId
 import com.ichi2.widget.ACTION_UPDATE_WIDGET
 import com.ichi2.widget.AnalyticsWidgetProvider
 import com.ichi2.widget.cancelRecurringAlarm
@@ -37,7 +38,6 @@
 import kotlinx.coroutines.launch
 import timber.log.Timber
 
-typealias DeckId = Long
 typealias AppWidgetId = Int
 
 /**
@@ -49,7 +49,7 @@
  * @property learnCount The number of cards in the learning phase.
  * @property newCount The number of new cards.
  */
-data class DeckPickerWidgetData(
+data class DeckWidgetData(
     val deckId: DeckId,
     val name: String,
     val reviewCount: Int,
@@ -97,7 +97,7 @@
             val remoteViews = RemoteViews(context.packageName, R.layout.widget_deck_picker_large)
 
             AnkiDroidApp.applicationScope.launch {
-                val deckData = getDeckNameAndStats(deckIds.toList())
+                val deckData = getDeckNamesAndStats(deckIds.toList())
 
                 remoteViews.removeAllViews(R.id.deckCollection)
 
@@ -277,15 +277,19 @@
  * @param deckIds the list of deck IDs to retrieve data for
  * @return a list of DeckPickerWidgetData objects containing deck names and statistics
  */
-suspend fun getDeckNameAndStats(deckIds: List<DeckId>): List<DeckPickerWidgetData> {
-    val result = mutableListOf<DeckPickerWidgetData>()
+suspend fun getDeckNameAndStats(deckId:DeckId): DeckWidgetData? {
+    return getDeckNamesAndStats(listOf(deckId)).getOrNull(0)
+}
+
+suspend fun getDeckNamesAndStats(deckIds: List<DeckId>): List<DeckWidgetData> {
+    val result = mutableListOf<DeckWidgetData>()
 
     val deckTree = withCol { sched.deckDueTree() }
 
     deckTree.forEach { node ->
         if (node.did !in deckIds) return@forEach
         result.add(
-            DeckPickerWidgetData(
+            DeckWidgetData(
                 deckId = node.did,
                 name = node.lastDeckNameComponent,
                 reviewCount = node.revCount,

Arthur-Milchior avatar Aug 30 '24 22:08 Arthur-Milchior

To save you time, here are the typing change I created while reviewing and testing your code

Thanks a lot for this, really helped me as my exams are around the corner.

xenonnn4w avatar Aug 31 '24 11:08 xenonnn4w

you shouldn't be able to close the list of decks except by selecting a deck. Closing the list, e.g. with "esc" should close the whole configuration. Remove the + symbol. It won't be used.

Is it possible to implement this change in future?. Need some time for my exam. I tried but wasn't able to implement that on back press the config screen should get closed not the deck selection dialog. I did implement the alternate mechanism for now.

xenonnn4w avatar Aug 31 '24 12:08 xenonnn4w

@xenonnn4w after checking with David, fine for doing the configuration change in the future

Arthur-Milchior avatar Sep 03 '24 16:09 Arthur-Milchior

  • https://github.com/ankidroid/Anki-Android/actions/runs/10760675211
  • https://github.com/ankidroid/Anki-Android/pull/17039

david-allison avatar Sep 08 '24 14:09 david-allison

Maintainers: Please Sync Translations to produce a commit with only the automated changes from this PR.

Read more about updating strings on the wiki,

github-actions[bot] avatar Sep 08 '24 19:09 github-actions[bot]

Hi there @xenonnn4w! This is the OpenCollective Notice for PRs merged from 2024-09-01 through 2024-09-30

If you are interested in compensation for this work, the process with details is here:

https://github.com/ankidroid/Anki-Android/wiki/OpenCollective-Payment-Process#how-to-get-paid

[!IMPORTANT] PLEASE NOTE: The process was updated in August 2024. Re-read the Payment Process page if you have not already.

We only post one comment per person per month to avoid spamming you, regardless of the number of PRs merged, but this note applies to all PRs merged for this month

Please understand that our monthly budget is never guaranteed to cover all claims - the cap on payments-per-person may be lower, but we try to make our process as fair and transparent as possible, we just need your understanding.

Thanks!

github-actions[bot] avatar Oct 01 '24 19:10 github-actions[bot]