Skip to content

Commit 4f5c099

Browse files
committed
Improve MarketWidgetWorker to use enqueuePeriodicRefresh and enqueueRefresh methods for widget updates
1 parent 920520e commit 4f5c099

5 files changed

Lines changed: 72 additions & 28 deletions

File tree

app/src/main/java/cash/p/terminal/core/App.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -519,7 +519,7 @@ class App : CoreApp(), WorkConfiguration.Provider, SingletonImageLoader.Factory
519519
AppVersionManager(systemInfoManager, localStorage).apply { storeAppVersion() }
520520

521521
if (MarketWidgetWorker.hasEnabledWidgets(instance)) {
522-
MarketWidgetWorker.enqueueWork(instance)
522+
MarketWidgetWorker.enqueuePeriodicRefresh(instance)
523523
} else {
524524
MarketWidgetWorker.cancel(instance)
525525
}

app/src/main/java/cash/p/terminal/widgets/MarketWidget.kt

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ import androidx.glance.appwidget.cornerRadius
2525
import androidx.glance.appwidget.lazy.LazyColumn
2626
import androidx.glance.appwidget.lazy.items
2727
import androidx.glance.appwidget.provideContent
28-
import androidx.glance.appwidget.state.updateAppWidgetState
2928
import androidx.glance.background
3029
import androidx.glance.currentState
3130
import androidx.glance.layout.Alignment
@@ -328,12 +327,7 @@ class UpdateMarketAction : ActionCallback {
328327
glanceId: GlanceId,
329328
parameters: ActionParameters
330329
) {
331-
updateAppWidgetState(context, MarketWidgetStateDefinition, glanceId) { state ->
332-
state.copy(loading = true)
333-
}
334-
MarketWidget().update(context, glanceId)
335-
336-
App.marketWidgetManager.refresh(glanceId)
330+
MarketWidgetWorker.enqueueRefresh(context, glanceId)
337331
}
338332
}
339333

app/src/main/java/cash/p/terminal/widgets/MarketWidgetConfigurationActivity.kt

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ import androidx.glance.GlanceId
3535
import androidx.glance.appwidget.GlanceAppWidgetManager
3636
import androidx.glance.appwidget.state.updateAppWidgetState
3737
import cash.p.terminal.R
38-
import cash.p.terminal.core.App
3938
import cash.p.terminal.strings.helpers.TranslatableString
4039
import cash.p.terminal.ui_compose.components.AppBar
4140
import cash.p.terminal.ui_compose.components.CellSingleLineLawrenceSection
@@ -144,8 +143,8 @@ class MarketWidgetConfigurationActivity : AppCompatActivity() {
144143
it.copy(widgetId = appWidgetId, type = selectedType)
145144
}
146145
MarketWidget().update(context, glanceId)
147-
App.marketWidgetManager.refresh(glanceId)
148-
MarketWidgetWorker.enqueueWork(App.instance)
146+
MarketWidgetWorker.enqueueRefresh(context, glanceId)
147+
MarketWidgetWorker.enqueuePeriodicRefresh(context)
149148
}
150149

151150
val resultValue = Intent().putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId)

app/src/main/java/cash/p/terminal/widgets/MarketWidgetManager.kt

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import coil3.request.ErrorResult
1010
import coil3.request.ImageRequest
1111
import cash.p.terminal.R
1212
import cash.p.terminal.core.App
13+
import kotlinx.coroutines.CancellationException
1314
import kotlinx.coroutines.CoroutineScope
1415
import kotlinx.coroutines.Dispatchers
1516
import kotlinx.coroutines.SupervisorJob
@@ -37,18 +38,21 @@ class MarketWidgetManager {
3738
}
3839
}
3940

40-
fun refresh(glanceId: GlanceId) {
41-
coroutineScope.launch {
42-
refreshSync(glanceId)
43-
}
44-
}
45-
46-
suspend fun refreshSync(glanceId: GlanceId) = withContext(Dispatchers.IO) {
41+
suspend fun refreshSync(
42+
glanceId: GlanceId,
43+
showLoading: Boolean = false
44+
) = withContext(Dispatchers.IO) {
4745
val context = App.instance
4846
try {
47+
if (showLoading) {
48+
val state = getAppWidgetState(context, MarketWidgetStateDefinition, glanceId)
49+
setWidgetState(context, glanceId, state.copy(loading = true))
50+
}
4951
executeWithRetry {
5052
updateData(glanceId)
5153
}
54+
} catch (exception: CancellationException) {
55+
throw exception
5256
} catch (exception: Exception) {
5357
var state = getAppWidgetState(context, MarketWidgetStateDefinition, glanceId)
5458

@@ -141,6 +145,8 @@ class MarketWidgetManager {
141145
try {
142146
call.invoke()
143147
break
148+
} catch (e: CancellationException) {
149+
throw e
144150
} catch (e: Exception) {
145151
delay(2000)
146152

app/src/main/java/cash/p/terminal/widgets/MarketWidgetWorker.kt

Lines changed: 55 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,22 @@ package cash.p.terminal.widgets
33
import android.appwidget.AppWidgetManager
44
import android.content.ComponentName
55
import android.content.Context
6+
import android.os.Build
7+
import androidx.glance.GlanceId
68
import androidx.glance.appwidget.GlanceAppWidgetManager
9+
import androidx.work.Constraints
710
import androidx.work.CoroutineWorker
811
import androidx.work.ExistingPeriodicWorkPolicy
12+
import androidx.work.ExistingWorkPolicy
13+
import androidx.work.NetworkType
14+
import androidx.work.OneTimeWorkRequestBuilder
15+
import androidx.work.OutOfQuotaPolicy
916
import androidx.work.PeriodicWorkRequestBuilder
1017
import androidx.work.WorkManager
1118
import androidx.work.WorkerParameters
12-
import cash.p.terminal.core.App
19+
import androidx.work.workDataOf
20+
import cash.p.terminal.core.getKoinInstance
21+
import cash.p.terminal.core.tryOrNull
1322
import kotlinx.coroutines.async
1423
import kotlinx.coroutines.awaitAll
1524
import kotlinx.coroutines.coroutineScope
@@ -20,24 +29,48 @@ class MarketWidgetWorker(
2029
workerParameters: WorkerParameters
2130
) : CoroutineWorker(context, workerParameters) {
2231

32+
private val marketWidgetManager: MarketWidgetManager by lazy { getKoinInstance() }
33+
2334
companion object {
2435
private const val updatePeriodMillis: Long = 15 * 60 * 1000 // 15 minutes
25-
private const val workName = "widget_update_work"
36+
private const val periodicWorkName = "widget_update_work"
37+
private const val refreshWorkName = "widget_refresh_work"
38+
private const val appWidgetIdKey = "app_widget_id"
39+
private val networkConstraints = Constraints.Builder()
40+
.setRequiredNetworkType(NetworkType.CONNECTED)
41+
.build()
2642

27-
fun enqueueWork(context: Context) {
43+
fun enqueuePeriodicRefresh(context: Context) {
2844
val manager = WorkManager.getInstance(context)
2945
val requestBuilder = PeriodicWorkRequestBuilder<MarketWidgetWorker>(Duration.ofMillis(updatePeriodMillis))
46+
.setConstraints(networkConstraints)
3047

3148
manager.enqueueUniquePeriodicWork(
32-
workName,
49+
periodicWorkName,
3350
ExistingPeriodicWorkPolicy.UPDATE,
3451
requestBuilder.build()
3552
)
3653
}
3754

55+
fun enqueueRefresh(context: Context, glanceId: GlanceId) {
56+
val appWidgetId = GlanceAppWidgetManager(context).getAppWidgetId(glanceId)
57+
val requestBuilder = OneTimeWorkRequestBuilder<MarketWidgetWorker>()
58+
.setInputData(workDataOf(appWidgetIdKey to appWidgetId))
59+
.setConstraints(networkConstraints)
60+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
61+
requestBuilder.setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)
62+
}
63+
64+
WorkManager.getInstance(context).enqueueUniqueWork(
65+
"$refreshWorkName:$appWidgetId",
66+
ExistingWorkPolicy.KEEP,
67+
requestBuilder.build()
68+
)
69+
}
70+
3871
fun cancel(context: Context) {
3972
if (!hasEnabledWidgets(context)) {
40-
WorkManager.getInstance(context).cancelUniqueWork(workName)
73+
WorkManager.getInstance(context).cancelUniqueWork(periodicWorkName)
4174
}
4275
}
4376

@@ -59,14 +92,26 @@ class MarketWidgetWorker(
5992
}
6093

6194
override suspend fun doWork(): Result = coroutineScope {
62-
val manager = GlanceAppWidgetManager(context)
63-
val glanceIds = manager.getGlanceIds(MarketWidget::class.java)
64-
65-
glanceIds.map { glanceId ->
66-
async { App.marketWidgetManager.refreshSync(glanceId) }
95+
val appWidgetId = inputData.getInt(appWidgetIdKey, AppWidgetManager.INVALID_APPWIDGET_ID)
96+
targetGlanceIds(appWidgetId).map { glanceId ->
97+
async {
98+
marketWidgetManager.refreshSync(
99+
glanceId = glanceId,
100+
showLoading = appWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID
101+
)
102+
}
67103
}.awaitAll()
68104

69105
Result.success()
70106
}
71107

108+
private suspend fun targetGlanceIds(appWidgetId: Int): List<GlanceId> {
109+
val manager = GlanceAppWidgetManager(context)
110+
if (appWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID) {
111+
return manager.getGlanceIds(MarketWidget::class.java)
112+
}
113+
114+
return listOfNotNull(tryOrNull { manager.getGlanceIdBy(appWidgetId) })
115+
}
116+
72117
}

0 commit comments

Comments
 (0)