diff --git a/AnkiDroid/src/main/AndroidManifest.xml b/AnkiDroid/src/main/AndroidManifest.xml index 98f68084e05e..c0e209902da1 100644 --- a/AnkiDroid/src/main/AndroidManifest.xml +++ b/AnkiDroid/src/main/AndroidManifest.xml @@ -523,7 +523,7 @@ /> - { val appWidgetManager = AppWidgetManager.getInstance(context) + + /** + * Array of widget IDs that need to be updated. + * + * When the `ACTION_APPWIDGET_UPDATE` intent is broadcast, it may include multiple widget IDs + * if there are multiple instances of the widget on the user's home screen. This array + * (`appWidgetIds`) represents those widget instances that need to be updated. + * + * Handling multiple widget IDs is necessary because users can add multiple instances of the + * same widget, and the system updates them together. The loop through this array ensures + * that each widget is updated individually. + */ val appWidgetIds = intent.getIntArrayExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS) - val selectedDeckIds = intent.getLongArrayExtra("deck_picker_widget_selected_deck_ids") + val selectedDeckIds = intent.getLongArrayExtra(EXTRA_SELECTED_DECK_IDS) - if (appWidgetIds != null && selectedDeckIds != null) { - for (appWidgetId in appWidgetIds) { - updateWidget(context, appWidgetManager, appWidgetId, selectedDeckIds) - } + if (appWidgetIds == null || selectedDeckIds == null) { + return + } + + for (appWidgetId in appWidgetIds) { + updateWidget(context, appWidgetManager, appWidgetId, selectedDeckIds) } } // This custom action is received to update a specific widget. diff --git a/AnkiDroid/src/main/java/com/ichi2/widget/DeckPickerWidgetConfig.kt b/AnkiDroid/src/main/java/com/ichi2/widget/DeckPickerWidgetConfig.kt index 274557d444ce..b21987440adf 100644 --- a/AnkiDroid/src/main/java/com/ichi2/widget/DeckPickerWidgetConfig.kt +++ b/AnkiDroid/src/main/java/com/ichi2/widget/DeckPickerWidgetConfig.kt @@ -49,7 +49,7 @@ import timber.log.Timber * Activity for configuring the Deck Picker Widget. * This activity allows the user to select decks from deck selection dialog to be displayed in the widget. * User can Select up to 5 decks. - * User Can remove, reorder decks and reconfigure by holding the widget . + * User Can remove, reorder decks and reconfigure by holding the widget. */ class DeckPickerWidgetConfig : AnkiActivity(), DeckSelectionListener { @@ -85,6 +85,7 @@ class DeckPickerWidgetConfig : AnkiActivity(), DeckSelectionListener { deckAdapter.removeDeck(position) showSnackbar(R.string.deck_removed_from_widget) updateViewVisibility() + updateFabVisibility() hasUnsavedChanges = true // Set flag when deck is removed } @@ -172,6 +173,16 @@ class DeckPickerWidgetConfig : AnkiActivity(), DeckSelectionListener { unregisterReceiverSilently(widgetRemovedReceiver) } + /** Updates the visibility of the FloatingActionButton based on the number of selected decks */ + private fun updateFabVisibility() { + val fab = findViewById(R.id.fabWidgetDeckPicker) + fab.visibility = if (deckAdapter.itemCount >= MAX_DECKS_ALLOWED) { + View.GONE + } else { + View.VISIBLE + } + } + /** Loads saved preferences and updates the RecyclerView */ fun loadSavedPreferences() { val selectedDeckIds = deckPickerWidgetPreferences.getSelectedDeckIdsFromPreferencesDeckPickerWidget(appWidgetId) @@ -181,6 +192,7 @@ class DeckPickerWidgetConfig : AnkiActivity(), DeckSelectionListener { val selectedDecks = decks.filter { it.deckId in selectedDeckIds } selectedDecks.forEach { deckAdapter.addDeck(it) } updateViewVisibility() + updateFabVisibility() } } } @@ -217,13 +229,36 @@ class DeckPickerWidgetConfig : AnkiActivity(), DeckSelectionListener { return } - if (deckAdapter.itemCount >= MAX_DECKS_ALLOWED) { - val message = resources.getQuantityString(R.plurals.deck_limit_reached, MAX_DECKS_ALLOWED, MAX_DECKS_ALLOWED) + // Check if the deck is already in the list + val isDeckAlreadySelected = deckAdapter.deckIds.contains(deck.deckId) + + if (isDeckAlreadySelected) { + // Show snackbar if the deck is already selected + val message = getString(R.string.deck_already_selected_message) showSnackbar(message) + return + } + + // Check if the deck is being added to a fully occupied selection + if (deckAdapter.itemCount >= MAX_DECKS_ALLOWED) { + // Snackbar will only be shown when adding the 5th deck + if (deckAdapter.itemCount == MAX_DECKS_ALLOWED) { + val message = resources.getQuantityString(R.plurals.deck_limit_reached, MAX_DECKS_ALLOWED, MAX_DECKS_ALLOWED) + showSnackbar(message) + } + // The FAB visibility should be handled in updateFabVisibility() } else { + // Add the deck and update views deckAdapter.addDeck(deck) updateViewVisibility() + updateFabVisibility() // Ensure FAB visibility is updated when deck is added hasUnsavedChanges = true // Set flag when deck is added + + // Show snackbar if the deck is the 5th deck + if (deckAdapter.itemCount == MAX_DECKS_ALLOWED) { + val message = resources.getQuantityString(R.plurals.deck_limit_reached, MAX_DECKS_ALLOWED, MAX_DECKS_ALLOWED) + showSnackbar(message) + } } } @@ -271,15 +306,18 @@ class DeckPickerWidgetConfig : AnkiActivity(), DeckSelectionListener { * It then sends a broadcast to update the widget with the new deck selection. */ fun saveSelectedDecksToPreferencesDeckPickerWidget() { - // Get the list of selected deck IDs as strings - val selectedDecks = deckAdapter.deckIds.map { it.toString() } - deckPickerWidgetPreferences.saveSelectedDecks(appWidgetId, selectedDecks) + // Get the list of selected deck IDs as Long + val selectedDecks = deckAdapter.deckIds.map { it } + + // Save the selected deck IDs as a comma-separated string + deckPickerWidgetPreferences.saveSelectedDecks(appWidgetId, selectedDecks.map { it.toString() }) + val updateIntent = Intent(this, DeckPickerWidget::class.java).apply { action = AppWidgetManager.ACTION_APPWIDGET_UPDATE putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, intArrayOf(appWidgetId)) - // Pass the selected deck IDs as a long array in the intent - putExtra("deck_picker_widget_selected_deck_ids", selectedDecks.map { it.toLong() }.toLongArray()) + // Pass the selected deck IDs as a List in the intent + putExtra("deck_picker_widget_selected_deck_ids", selectedDecks.toList().toLongArray()) } // Send the broadcast to update the widget diff --git a/AnkiDroid/src/main/res/values/08-widget.xml b/AnkiDroid/src/main/res/values/08-widget.xml index 0b542979b670..d8eebad92bec 100644 --- a/AnkiDroid/src/main/res/values/08-widget.xml +++ b/AnkiDroid/src/main/res/values/08-widget.xml @@ -42,20 +42,21 @@ Select decks - Select decks to display in the widgets - Select decks with the + icon. - Deck Removed - No decks available to select" + Select decks to display in the widget + Select decks with the + icon. + Deck Removed + No decks available to select" Keep Editing Discard current input? + This deck is already selected - You can select up to %d decks. + You can select up to %d deck. You can select up to %d decks. - English - Español - 日本語 + English + Español + 日本語