From 7277ff26fc36f992e37dc43fdb57201707d00974 Mon Sep 17 00:00:00 2001 From: Sylvia van Os Date: Sun, 13 Jul 2025 23:24:40 +0200 Subject: [PATCH] Refactor deprecated widget code This replaces the deprecated widget method with the new one and ensures it consistently updates on changes. --- app/build.gradle.kts | 1 + app/src/main/AndroidManifest.xml | 4 - .../card_locker/CatimaRemoteViewsService.kt | 110 ------------------ .../java/protect/card_locker/CatimaWidget.kt | 90 +++++++++++++- .../card_locker/LoyaltyCardViewActivity.java | 4 + .../protect/card_locker/MainActivity.java | 8 +- 6 files changed, 91 insertions(+), 126 deletions(-) delete mode 100644 app/src/main/java/protect/card_locker/CatimaRemoteViewsService.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 32749ea0f..7446d69ab 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -112,6 +112,7 @@ dependencies { implementation("androidx.appcompat:appcompat:1.7.1") implementation("androidx.constraintlayout:constraintlayout:2.2.1") implementation("androidx.core:core-ktx:1.16.0") + implementation("androidx.core:core-remoteviews:1.1.0") implementation("androidx.core:core-splashscreen:1.0.1") implementation("androidx.exifinterface:exifinterface:1.4.1") implementation("androidx.palette:palette:1.0.0") diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index a65683a29..adb39906a 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -218,9 +218,5 @@ - - diff --git a/app/src/main/java/protect/card_locker/CatimaRemoteViewsService.kt b/app/src/main/java/protect/card_locker/CatimaRemoteViewsService.kt deleted file mode 100644 index d4ca18443..000000000 --- a/app/src/main/java/protect/card_locker/CatimaRemoteViewsService.kt +++ /dev/null @@ -1,110 +0,0 @@ -package protect.card_locker - -import android.content.Context -import android.content.Intent -import android.database.sqlite.SQLiteDatabase -import android.graphics.Color -import android.graphics.drawable.Icon -import android.os.Build -import android.view.View -import android.widget.RemoteViews -import android.widget.RemoteViewsService -import protect.card_locker.DBHelper.LoyaltyCardArchiveFilter -import kotlin.math.max - -class CatimaWidgetRemoteViewsFactory(private var context: Context) : - RemoteViewsService.RemoteViewsFactory { - - private var mDatabase: SQLiteDatabase = DBHelper(context).readableDatabase - - override fun onCreate() { - onDataSetChanged() - } - - private var mCards: ArrayList = ArrayList() - - override fun onDataSetChanged() { - val mOrder = Utils.getLoyaltyCardOrder(context); - val mOrderDirection = Utils.getLoyaltyCardOrderDirection(context); - - val cur = DBHelper.getLoyaltyCardCursor( - mDatabase, - "", - null, - mOrder, - mOrderDirection, - LoyaltyCardArchiveFilter.Unarchived - ) - - mCards.clear() - if (cur.moveToFirst()) { - do { - val item = LoyaltyCard.fromCursor(context, cur) - mCards.add(item) - } while (cur.moveToNext()) - } - } - - override fun onDestroy() {} - - override fun getCount(): Int { - return max(1, mCards.count()) - } - - private fun createRemoteView(item: LoyaltyCard): RemoteViews - { - val rv = RemoteViews(context.packageName, R.layout.catima_widget_item).apply { - val headerColor = Utils.getHeaderColor(context, item) - val foreground = if (Utils.needsDarkForeground(headerColor)) Color.BLACK else Color.WHITE - setInt(R.id.item_container, "setBackgroundColor", headerColor) - val icon = item.getImageThumbnail(context) - // setImageViewIcon is not supported on Android 5, so force Android 5 down the text path - if (icon != null && Build.VERSION.SDK_INT >= 23) { - setInt(R.id.item_container, "setBackgroundColor", foreground) - setImageViewIcon(R.id.item_image, Icon.createWithBitmap(icon)) - setViewVisibility(R.id.item_text, View.INVISIBLE) - setViewVisibility(R.id.item_image, View.VISIBLE) - } else { - setImageViewBitmap(R.id.item_image, null) - setTextViewText(R.id.item_text, item.store) - setViewVisibility(R.id.item_text, View.VISIBLE) - setViewVisibility(R.id.item_image, View.INVISIBLE) - setTextColor( - R.id.item_text, - foreground - ) - } - - val fillInIntent = Intent().apply { - putExtra(LoyaltyCardViewActivity.BUNDLE_ID, item.id) - } - - setOnClickFillInIntent(R.id.item_container, fillInIntent) - } - - return rv - } - - override fun getViewAt(position: Int): RemoteViews { - if (mCards.isEmpty()) { - return RemoteViews(context.packageName, R.layout.catima_widget_empty) - } - - val item = mCards[position] - return createRemoteView(item) - } - - override fun getLoadingView(): RemoteViews? = null - - override fun getViewTypeCount(): Int = 1 - - override fun getItemId(position: Int): Long = position.toLong() - - override fun hasStableIds(): Boolean = true -} - -class CatimaRemoteViewsService : RemoteViewsService() { - override fun onGetViewFactory(intent: Intent?): RemoteViewsFactory { - return CatimaWidgetRemoteViewsFactory(applicationContext) - } -} \ No newline at end of file diff --git a/app/src/main/java/protect/card_locker/CatimaWidget.kt b/app/src/main/java/protect/card_locker/CatimaWidget.kt index 86b6c6070..d5984ecfa 100644 --- a/app/src/main/java/protect/card_locker/CatimaWidget.kt +++ b/app/src/main/java/protect/card_locker/CatimaWidget.kt @@ -3,22 +3,36 @@ package protect.card_locker import android.app.PendingIntent import android.appwidget.AppWidgetManager import android.appwidget.AppWidgetProvider +import android.content.ComponentName import android.content.Context import android.content.Intent +import android.graphics.Color +import android.graphics.drawable.Icon +import android.os.Build +import android.view.View import android.widget.RemoteViews +import androidx.core.widget.RemoteViewsCompat +import protect.card_locker.DBHelper.LoyaltyCardArchiveFilter class CatimaWidget : AppWidgetProvider() { + fun updateAll(context: Context) { + val appWidgetManager = AppWidgetManager.getInstance(context) + val componentName = ComponentName(context, CatimaWidget::class.java) + onUpdate( + context, + appWidgetManager, + appWidgetManager.getAppWidgetIds(componentName) + ) + } + override fun onUpdate( context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray ) { for (appWidgetId in appWidgetIds) { + // Prepare generic widget val views = RemoteViews(context.packageName, R.layout.catima_widget) - val intent = Intent(context, CatimaRemoteViewsService::class.java) - intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId) - views.setRemoteAdapter(R.id.grid_view, intent) - val templateIntent = Intent(context, LoyaltyCardViewActivity::class.java) val pendingIntent = PendingIntent.getActivity( context, @@ -26,9 +40,75 @@ class CatimaWidget : AppWidgetProvider() { templateIntent, PendingIntent.FLAG_MUTABLE or PendingIntent.FLAG_UPDATE_CURRENT ) - views.setPendingIntentTemplate(R.id.grid_view, pendingIntent) + + // Get cards + val order = Utils.getLoyaltyCardOrder(context); + val orderDirection = Utils.getLoyaltyCardOrderDirection(context); + val database = DBHelper(context).readableDatabase + + val loyaltyCardCursor = DBHelper.getLoyaltyCardCursor( + database, + "", + null, + order, + orderDirection, + LoyaltyCardArchiveFilter.Unarchived + ) + + // Bind every card to cell in the grid + val remoteCollectionItemsBuilder = RemoteViewsCompat.RemoteCollectionItems.Builder() + if (loyaltyCardCursor.moveToFirst()) { + do { + val loyaltyCard = LoyaltyCard.fromCursor(context, loyaltyCardCursor) + remoteCollectionItemsBuilder.addItem( + loyaltyCard.id.toLong(), + createRemoteViews( + context, loyaltyCard + ) + ) + } while (loyaltyCardCursor.moveToNext()) + } + RemoteViewsCompat.setRemoteAdapter(context, views, appWidgetId, R.id.grid_view, remoteCollectionItemsBuilder.build()) + + // Let Android know the widget is ready for display appWidgetManager.updateAppWidget(appWidgetId, views) } } + + private fun createRemoteViews(context: Context, loyaltyCard: LoyaltyCard): RemoteViews { + // Create a single cell for the grid view, bind it to open in the LoyaltyCardViewActivity + // Note: Android 5 will not use bitmaps + val remoteViews = RemoteViews(context.packageName, R.layout.catima_widget_item).apply { + val headerColor = Utils.getHeaderColor(context, loyaltyCard) + val foreground = if (Utils.needsDarkForeground(headerColor)) Color.BLACK else Color.WHITE + setInt(R.id.item_container, "setBackgroundColor", headerColor) + val icon = loyaltyCard.getImageThumbnail(context) + // setImageViewIcon is not supported on Android 5, so force Android 5 down the text path + if (icon != null && Build.VERSION.SDK_INT >= 23) { + setInt(R.id.item_container, "setBackgroundColor", foreground) + setImageViewIcon(R.id.item_image, Icon.createWithBitmap(icon)) + setViewVisibility(R.id.item_text, View.INVISIBLE) + setViewVisibility(R.id.item_image, View.VISIBLE) + } else { + setImageViewBitmap(R.id.item_image, null) + setTextViewText(R.id.item_text, loyaltyCard.store) + setViewVisibility(R.id.item_text, View.VISIBLE) + setViewVisibility(R.id.item_image, View.INVISIBLE) + setTextColor( + R.id.item_text, + foreground + ) + } + + // Add the card ID to the intent template + val fillInIntent = Intent().apply { + putExtra(LoyaltyCardViewActivity.BUNDLE_ID, loyaltyCard.id) + } + + setOnClickFillInIntent(R.id.item_container, fillInIntent) + } + + return remoteViews + } } \ No newline at end of file diff --git a/app/src/main/java/protect/card_locker/LoyaltyCardViewActivity.java b/app/src/main/java/protect/card_locker/LoyaltyCardViewActivity.java index eeb9383ba..4317c4f11 100644 --- a/app/src/main/java/protect/card_locker/LoyaltyCardViewActivity.java +++ b/app/src/main/java/protect/card_locker/LoyaltyCardViewActivity.java @@ -880,6 +880,8 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements } else if (id == R.id.action_star_unstar) { DBHelper.updateLoyaltyCardStarStatus(database, loyaltyCardId, loyaltyCard.starStatus == 0 ? 1 : 0); + new CatimaWidget().updateAll(LoyaltyCardViewActivity.this); + // Re-init loyaltyCard with new data from DB onResume(); invalidateOptionsMenu(); @@ -890,6 +892,7 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements Toast.makeText(LoyaltyCardViewActivity.this, R.string.archived, Toast.LENGTH_LONG).show(); ShortcutHelper.removeShortcut(LoyaltyCardViewActivity.this, loyaltyCardId); + new CatimaWidget().updateAll(LoyaltyCardViewActivity.this); // Re-init loyaltyCard with new data from DB onResume(); @@ -915,6 +918,7 @@ public class LoyaltyCardViewActivity extends CatimaAppCompatActivity implements DBHelper.deleteLoyaltyCard(database, LoyaltyCardViewActivity.this, loyaltyCardId); ShortcutHelper.removeShortcut(LoyaltyCardViewActivity.this, loyaltyCardId); + new CatimaWidget().updateAll(LoyaltyCardViewActivity.this); finish(); dialog.dismiss(); diff --git a/app/src/main/java/protect/card_locker/MainActivity.java b/app/src/main/java/protect/card_locker/MainActivity.java index 9adc8ee10..70f49638b 100644 --- a/app/src/main/java/protect/card_locker/MainActivity.java +++ b/app/src/main/java/protect/card_locker/MainActivity.java @@ -431,13 +431,7 @@ public class MainActivity extends CatimaAppCompatActivity implements LoyaltyCard mCurrentActionMode.finish(); } - updateWidget(mAdapter.mContext); - } - - private void updateWidget(Context context) { - AppWidgetManager manager = AppWidgetManager.getInstance(context); - int[] ids = manager.getAppWidgetIds(new ComponentName(context, CatimaWidget.class)); - manager.notifyAppWidgetViewDataChanged(ids, R.id.grid_view); + new CatimaWidget().updateAll(mAdapter.mContext); } private void processParseResultList(List parseResultList, String group, boolean closeAppOnNoBarcode) {