Skip to content

Commit

Permalink
Removing the 'extra' and refactoring deckIds to deckId.
Browse files Browse the repository at this point in the history
  • Loading branch information
xenonnn4w committed Aug 28, 2024
1 parent a77e815 commit 95cb577
Show file tree
Hide file tree
Showing 11 changed files with 113 additions and 118 deletions.
6 changes: 3 additions & 3 deletions AnkiDroid/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -550,7 +550,7 @@
<!-- A widget that displays a deck name and number of cards to review on the Android home screen.
The way to add it depends on the phone. It usually consists in a long press on the screen, followed by finding a "widget" button"-->
<receiver
android:name="com.ichi2.widget.cardanalysis.CardAnalysisExtraWidget"
android:name="com.ichi2.widget.cardanalysis.CardAnalysisWidget"
android:label="@string/card_analysis_extra_widget_description"
android:exported="false"
>
Expand All @@ -560,14 +560,14 @@

<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/widget_provider_card_analysis_extra" />
android:resource="@xml/widget_provider_card_analysis" />
</receiver>

<!-- Configuration view for the CardAnalysisExtraWidget above.
It is opened when adding a new widget and
by configuration button which appears when the widget is hold or resized.-->
<activity
android:name="com.ichi2.widget.cardanalysis.CardAnalysisExtraWidgetConfig"
android:name="com.ichi2.widget.cardanalysis.CardAnalysisWidgetConfig"
android:exported="false">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
Expand Down
4 changes: 2 additions & 2 deletions AnkiDroid/src/main/java/com/ichi2/anki/AnkiDroidApp.kt
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ import com.ichi2.utils.ExceptionUtil
import com.ichi2.utils.KotlinCleanup
import com.ichi2.utils.LanguageUtil
import com.ichi2.utils.Permissions
import com.ichi2.widget.cardanalysis.CardAnalysisExtraWidget
import com.ichi2.widget.cardanalysis.CardAnalysisWidget
import com.ichi2.widget.deckpicker.DeckPickerWidget
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
Expand Down Expand Up @@ -299,7 +299,7 @@ open class AnkiDroidApp : Application(), Configuration.Provider, ChangeManager.S
Timber.d("ChangeSubscriber - opExecuted called with changes: $changes")
if (changes.studyQueues) {
DeckPickerWidget.updateDeckPickerWidgets(this)
CardAnalysisExtraWidget.updateCardAnalysisExtraWidgets(this)
CardAnalysisWidget.updateCardAnalysisWidgets(this)
} else {
Timber.d("No relevant changes to update the widget")
}
Expand Down
24 changes: 12 additions & 12 deletions AnkiDroid/src/main/java/com/ichi2/widget/WidgetPreferences.kt
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class WidgetPreferences(context: Context) {

private val deckPickerSharedPreferences = context.getSharedPreferences("DeckPickerWidgetPrefs", Context.MODE_PRIVATE)

private val cardAnalysisExtraWidgetSharedPreferences = context.getSharedPreferences("CardAnalysisExtraWidgetPrefs", Context.MODE_PRIVATE)
private val cardAnalysisWidgetSharedPreferences = context.getSharedPreferences("CardAnalysisWidgetPrefs", Context.MODE_PRIVATE)

/**
* Deletes the selected deck IDs from the shared preferences for the given widget ID.
Expand Down Expand Up @@ -69,15 +69,15 @@ class WidgetPreferences(context: Context) {
}
}

fun deleteCardAnalysisExtraWidgetData(appWidgetId: Int) {
cardAnalysisExtraWidgetSharedPreferences.edit {
remove(getCardAnalysisExtraWidgetKey(appWidgetId))
fun deleteCardAnalysisWidgetData(appWidgetId: Int) {
cardAnalysisWidgetSharedPreferences.edit {
remove(getCardAnalysisWidgetKey(appWidgetId))
}
}

fun getSelectedDeckIdsFromPreferencesCardAnalysisExtraWidget(appWidgetId: Int): LongArray {
val selectedDecksString = cardAnalysisExtraWidgetSharedPreferences.getString(
getCardAnalysisExtraWidgetKey(appWidgetId),
fun getSelectedDeckIdFromPreferencesCardAnalysisWidget(appWidgetId: Int): LongArray {
val selectedDecksString = cardAnalysisWidgetSharedPreferences.getString(
getCardAnalysisWidgetKey(appWidgetId),
""
)
return if (!selectedDecksString.isNullOrEmpty()) {
Expand All @@ -87,9 +87,9 @@ class WidgetPreferences(context: Context) {
}
}

fun saveSelectedDecksCardAnalysisExtraWidget(appWidgetId: Int, selectedDecks: List<String>) {
cardAnalysisExtraWidgetSharedPreferences.edit {
putString(getCardAnalysisExtraWidgetKey(appWidgetId), selectedDecks.joinToString(","))
fun saveSelectedDecksCardAnalysisWidget(appWidgetId: Int, selectedDecks: List<String>) {
cardAnalysisWidgetSharedPreferences.edit {
putString(getCardAnalysisWidgetKey(appWidgetId), selectedDecks.joinToString(","))
}
}
}
Expand All @@ -101,6 +101,6 @@ private fun getDeckPickerWidgetKey(appWidgetId: Int): String {
return "deck_picker_widget_selected_decks_$appWidgetId"
}

private fun getCardAnalysisExtraWidgetKey(appWidgetId: Int): String {
return "card_analysis_extra_widget_selected_decks_$appWidgetId"
private fun getCardAnalysisWidgetKey(appWidgetId: Int): String {
return "card_analysis_widget_selected_decks_$appWidgetId"
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,21 +32,18 @@ import com.ichi2.widget.ACTION_UPDATE_WIDGET
import com.ichi2.widget.AnalyticsWidgetProvider
import com.ichi2.widget.WidgetPreferences
import com.ichi2.widget.cancelRecurringAlarm
import com.ichi2.widget.deckpicker.AppWidgetId
import com.ichi2.widget.deckpicker.getDeckNameAndStats
import com.ichi2.widget.setRecurringAlarm
import kotlinx.coroutines.launch
import timber.log.Timber

typealias DeckId = Long

/**
* This widget displays a deck with the respective new, learning, and review card counts.
* It updates every minute and if there is any changes in study queues.
* It allows user to open the reviewer directly by clicking on the deck same as deckpicker.
* It can be configured and reconfigured by holding the widget.
*/
class CardAnalysisExtraWidget : AnalyticsWidgetProvider() {
class CardAnalysisWidget : AnalyticsWidgetProvider() {

companion object {
/**
Expand All @@ -56,83 +53,82 @@ class CardAnalysisExtraWidget : AnalyticsWidgetProvider() {
const val ACTION_APPWIDGET_UPDATE = AppWidgetManager.ACTION_APPWIDGET_UPDATE

/**
* Key used for passing the selected deck IDs in the intent extras.
* Key used for passing the selected deck ID in the intent extras.
*/
const val EXTRA_SELECTED_DECK_IDS = "card_analysis_extra_widget_selected_deck_ids"
const val EXTRA_SELECTED_DECK_ID = "card_analysis_widget_selected_deck_id"

/**
* Updates the widget with the deck data.
*
* This method replaces the entire view content with entries for each deck ID
* provided in the `deckIds` array. If any decks are deleted,
* they will be ignored, and only the rest of the decks will be displayed.
* This method updates the widget view content with the deck data corresponding
* to the provided deck ID. If the deck is deleted, the widget will be cleared.
*
* @param context the context of the application
* @param appWidgetManager the AppWidgetManager instance
* @param appWidgetId the ID of the app widget
* @param deckIds the array of deck IDs to be displayed in the widget.
* Each ID corresponds to a specific deck, and the view will
* contain exactly the decks whose IDs are in this list.
*
* @param deckId the ID of the deck to be displayed in the widget.
*/
fun updateWidget(
context: Context,
appWidgetManager: AppWidgetManager,
appWidgetId: AppWidgetId,
deckIds: LongArray
appWidgetId: Int,
deckId: LongArray
) {
val remoteViews = RemoteViews(context.packageName, R.layout.widget_card_analysis_extra)
val remoteViews = RemoteViews(context.packageName, R.layout.widget_card_analysis)

AnkiDroidApp.applicationScope.launch {
val deckData = getDeckNameAndStats(deckIds.toList())

if (deckData.isNotEmpty()) {
val deck = deckData[0]
remoteViews.setTextViewText(R.id.deckNameCardAnalysisExtra, deck.name)
remoteViews.setTextViewText(R.id.deckNew_card_analysis_extra_widget, deck.newCount.toString())
remoteViews.setTextViewText(R.id.deckDue_card_analysis_extra_widget, deck.reviewCount.toString())
remoteViews.setTextViewText(R.id.deckLearn_card_analysis_extra_widget, deck.learnCount.toString())

val isEmptyDeck = deck.newCount == 0 && deck.reviewCount == 0 && deck.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 deckData = getDeckNameAndStats(deckId.toList())

if (deckData.isEmpty()) {
appWidgetManager.updateAppWidget(appWidgetId, remoteViews)
return@launch
}

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())

val isEmptyDeck = deck.newCount == 0 && deck.reviewCount == 0 && deck.learnCount == 0

val intent = if (!isEmptyDeck) {
Intent(context, Reviewer::class.java).apply {
action = Intent.ACTION_VIEW
putExtra("deckId", deck.deckId)
}
val pendingIntent = PendingIntent.getActivity(
context,
deck.deckId.toInt(),
intent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
)
remoteViews.setOnClickPendingIntent(R.id.deckNameCardAnalysisExtra, pendingIntent)
} 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)

appWidgetManager.updateAppWidget(appWidgetId, remoteViews)
}
}

/**
* Updates the Card Analysis Widgets based on the current state of the application.
* It fetches the App Widget IDs and updates each widget with the associated deck IDs.
* It fetches the App Widget IDs and updates each widget with the associated deck ID.
*/
fun updateCardAnalysisExtraWidgets(context: Context) {
fun updateCardAnalysisWidgets(context: Context) {
val appWidgetManager = AppWidgetManager.getInstance(context)

val provider = ComponentName(context, CardAnalysisExtraWidget::class.java)
val provider = ComponentName(context, CardAnalysisWidget::class.java)
Timber.d("Fetching appWidgetIds for provider: $provider")

val appWidgetIds = appWidgetManager.getAppWidgetIds(provider)
Timber.d("AppWidgetIds to update: ${appWidgetIds.joinToString(", ")}")

for (appWidgetId in appWidgetIds) {
val widgetPreferences = WidgetPreferences(context)
val deckIds = widgetPreferences.getSelectedDeckIdsFromPreferencesCardAnalysisExtraWidget(appWidgetId)
updateWidget(context, appWidgetManager, appWidgetId, deckIds)
val deckId = widgetPreferences.getSelectedDeckIdFromPreferencesCardAnalysisWidget(appWidgetId)
updateWidget(context, appWidgetManager, appWidgetId, deckId)
}
}
}
Expand All @@ -149,20 +145,18 @@ class CardAnalysisExtraWidget : AnalyticsWidgetProvider() {

for (widgetId in appWidgetIds) {
Timber.d("Updating widget with ID: $widgetId")
val selectedDeckIds = widgetPreferences.getSelectedDeckIdsFromPreferencesCardAnalysisExtraWidget(widgetId)
val selectedDeckId = widgetPreferences.getSelectedDeckIdFromPreferencesCardAnalysisWidget(widgetId)

/**Explanation of behavior when selectedDeckIds is empty
* If selectedDeckIds is empty, the widget will retain the previous deck list.
/**Explanation of behavior when selectedDeckId is empty
* If selectedDeckId is empty, the widget will retain the previous deck.
* This behavior ensures that the widget does not display an empty view, which could be
* confusing to the user. Instead, it maintains the last known state until a new valid
* list of deck IDs is provided. This approach prioritizes providing a consistent
* deck ID is provided. This approach prioritizes providing a consistent
* user experience over showing an empty or default state.
*/
if (selectedDeckIds.isNotEmpty()) {
Timber.d("Selected deck IDs: ${selectedDeckIds.joinToString(", ")} for widget ID: $widgetId")
updateWidget(context, appWidgetManager, widgetId, selectedDeckIds)
}
setRecurringAlarm(context, widgetId, CardAnalysisExtraWidget::class.java)
Timber.d("Selected deck ID: $selectedDeckId for widget ID: $widgetId")
updateWidget(context, appWidgetManager, widgetId, selectedDeckId)
setRecurringAlarm(context, widgetId, CardAnalysisWidget::class.java)
}

Timber.d("Widget update process completed for appWidgetIds: ${appWidgetIds.joinToString(", ")}")
Expand All @@ -183,13 +177,14 @@ class CardAnalysisExtraWidget : AnalyticsWidgetProvider() {

// Retrieve the widget ID from the intent
val appWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID)
val selectedDeckIds = intent.getLongArrayExtra(EXTRA_SELECTED_DECK_IDS)
val selectedDeckId = intent.getLongExtra(EXTRA_SELECTED_DECK_ID, -1L)

Timber.d("Received ACTION_APPWIDGET_UPDATE with widget ID: $appWidgetId and selectedDeckIds: ${selectedDeckIds?.joinToString(", ")}")
Timber.d("Received ACTION_APPWIDGET_UPDATE with widget ID: $appWidgetId and selectedDeckId: $selectedDeckId")

if (appWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID && selectedDeckIds != null) {
if (appWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID && selectedDeckId != -1L) {
Timber.d("Updating widget with ID: $appWidgetId")
updateWidget(context, appWidgetManager, appWidgetId, selectedDeckIds)
// Wrap selectedDeckId into a LongArray
updateWidget(context, appWidgetManager, appWidgetId, longArrayOf(selectedDeckId))
Timber.d("Widget update process completed for widget ID: $appWidgetId")
}
}
Expand All @@ -206,8 +201,8 @@ class CardAnalysisExtraWidget : AnalyticsWidgetProvider() {
val appWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID)
if (appWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID) {
Timber.d("Deleting widget with ID: $appWidgetId")
cancelRecurringAlarm(context, appWidgetId, CardAnalysisExtraWidget::class.java)
widgetPreferences.deleteCardAnalysisExtraWidgetData(appWidgetId)
cancelRecurringAlarm(context, appWidgetId, CardAnalysisWidget::class.java)
widgetPreferences.deleteCardAnalysisWidgetData(appWidgetId)
} else {
Timber.e("Invalid widget ID received in ACTION_APPWIDGET_DELETED")
}
Expand All @@ -222,7 +217,7 @@ class CardAnalysisExtraWidget : AnalyticsWidgetProvider() {
Timber.e("Unexpected action received: ${intent.action}")
CrashReportService.sendExceptionReport(
Exception("Unexpected action received: ${intent.action}"),
"CardAnalysisExtraWidget - onReceive",
"CardAnalysisWidget - onReceive",
null,
onlyIfSilent = true
)
Expand All @@ -239,8 +234,8 @@ class CardAnalysisExtraWidget : AnalyticsWidgetProvider() {
val widgetPreferences = WidgetPreferences(context)

appWidgetIds?.forEach { widgetId ->
cancelRecurringAlarm(context, widgetId, CardAnalysisExtraWidget::class.java)
widgetPreferences.deleteCardAnalysisExtraWidgetData(widgetId)
cancelRecurringAlarm(context, widgetId, CardAnalysisWidget::class.java)
widgetPreferences.deleteCardAnalysisWidgetData(widgetId)
}
}
}
Loading

0 comments on commit 95cb577

Please sign in to comment.