summaryrefslogtreecommitdiff
path: root/android/app/src/main/java/org/terst/doot/widget
diff options
context:
space:
mode:
Diffstat (limited to 'android/app/src/main/java/org/terst/doot/widget')
-rw-r--r--android/app/src/main/java/org/terst/doot/widget/data/DataStore.kt2
-rw-r--r--android/app/src/main/java/org/terst/doot/widget/ui/Actions.kt21
-rw-r--r--android/app/src/main/java/org/terst/doot/widget/ui/DootWidget.kt34
-rw-r--r--android/app/src/main/java/org/terst/doot/widget/work/RefreshWorker.kt13
4 files changed, 62 insertions, 8 deletions
diff --git a/android/app/src/main/java/org/terst/doot/widget/data/DataStore.kt b/android/app/src/main/java/org/terst/doot/widget/data/DataStore.kt
index 164e3a2..d2f2cbb 100644
--- a/android/app/src/main/java/org/terst/doot/widget/data/DataStore.kt
+++ b/android/app/src/main/java/org/terst/doot/widget/data/DataStore.kt
@@ -3,6 +3,7 @@ package org.terst.doot.widget.data
import android.content.Context
import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.Preferences
+import androidx.datastore.preferences.core.booleanPreferencesKey
import androidx.datastore.preferences.core.longPreferencesKey
import androidx.datastore.preferences.core.stringPreferencesKey
import androidx.datastore.preferences.preferencesDataStore
@@ -15,4 +16,5 @@ object Keys {
val ITEMS_JSON = stringPreferencesKey("items_json")
val NOW = stringPreferencesKey("now")
val LAST_UPDATED = longPreferencesKey("last_updated")
+ val IS_REFRESHING = booleanPreferencesKey("is_refreshing")
}
diff --git a/android/app/src/main/java/org/terst/doot/widget/ui/Actions.kt b/android/app/src/main/java/org/terst/doot/widget/ui/Actions.kt
index 27a49e6..3a813fd 100644
--- a/android/app/src/main/java/org/terst/doot/widget/ui/Actions.kt
+++ b/android/app/src/main/java/org/terst/doot/widget/ui/Actions.kt
@@ -1,10 +1,15 @@
package org.terst.doot.widget.ui
import android.content.Context
+import androidx.datastore.preferences.core.edit
import androidx.glance.GlanceId
import androidx.glance.action.ActionParameters
import androidx.glance.appwidget.action.ActionCallback
+import androidx.glance.appwidget.updateAll
+import org.terst.doot.widget.data.Keys
+import org.terst.doot.widget.data.dataStore
import org.terst.doot.widget.work.CompleteWorker
+import org.terst.doot.widget.work.RefreshWorker
class CompleteTaskAction : ActionCallback {
override suspend fun onAction(
@@ -22,3 +27,19 @@ class CompleteTaskAction : ActionCallback {
val sourceKey = ActionParameters.Key<String>("item_source")
}
}
+
+// Sets IS_REFRESHING synchronously (before the network round trip) so the
+// widget's icon flips to the loading state on the spot -- RefreshWorker
+// clears the flag when it finishes, regardless of outcome, so the icon
+// never gets stuck.
+class RefreshTaskAction : ActionCallback {
+ override suspend fun onAction(
+ context: Context,
+ glanceId: GlanceId,
+ parameters: ActionParameters
+ ) {
+ context.dataStore.edit { it[Keys.IS_REFRESHING] = true }
+ DootWidget().updateAll(context)
+ RefreshWorker.runOnce(context)
+ }
+}
diff --git a/android/app/src/main/java/org/terst/doot/widget/ui/DootWidget.kt b/android/app/src/main/java/org/terst/doot/widget/ui/DootWidget.kt
index 7674ddb..7c84168 100644
--- a/android/app/src/main/java/org/terst/doot/widget/ui/DootWidget.kt
+++ b/android/app/src/main/java/org/terst/doot/widget/ui/DootWidget.kt
@@ -47,9 +47,10 @@ class DootWidget : GlanceAppWidget() {
val items = parseItems(prefs)
val now = prefs[Keys.NOW]?.let { runCatching { Instant.parse(it) }.getOrNull() }
?: Instant.now()
+ val isRefreshing = prefs[Keys.IS_REFRESHING] ?: false
provideContent {
- WidgetRoot(items, now)
+ WidgetRoot(items, now, isRefreshing)
}
}
@@ -60,7 +61,7 @@ class DootWidget : GlanceAppWidget() {
}
@Composable
-fun WidgetRoot(items: List<WidgetItem>, now: Instant) {
+fun WidgetRoot(items: List<WidgetItem>, now: Instant, isRefreshing: Boolean) {
val zone = ZoneId.systemDefault()
val nowZoned: ZonedDateTime = now.atZone(zone)
val todayStart = nowZoned.toLocalDate().atStartOfDay(zone).toInstant()
@@ -107,15 +108,20 @@ fun WidgetRoot(items: List<WidgetItem>, now: Instant) {
.background(Color.Transparent)
.padding(horizontal = 8.dp, vertical = 4.dp)
) {
- Row(modifier = GlanceModifier.fillMaxWidth().padding(bottom = 4.dp)) {
+ Row(
+ modifier = GlanceModifier.fillMaxWidth().padding(bottom = 4.dp),
+ verticalAlignment = Alignment.CenterVertically
+ ) {
Text(
"TODAY",
style = TextStyle(
color = ColorProvider(Color(0x66FFFFFF)),
fontSize = 11.sp,
fontWeight = FontWeight.Bold
- )
+ ),
+ modifier = GlanceModifier.defaultWeight()
)
+ RefreshButton(isRefreshing)
}
todayAllDay.forEach { AllDayRow(it) }
@@ -151,6 +157,26 @@ fun AllDayRow(event: WidgetItem) {
}
@Composable
+fun RefreshButton(isRefreshing: Boolean) {
+ Box(
+ modifier = GlanceModifier
+ .size(24.dp)
+ .clickable(actionRunCallback<RefreshTaskAction>()),
+ contentAlignment = Alignment.Center
+ ) {
+ Image(
+ provider = ImageProvider(
+ if (isRefreshing) org.terst.doot.widget.R.drawable.ic_refresh_loading
+ else org.terst.doot.widget.R.drawable.ic_refresh
+ ),
+ contentDescription = if (isRefreshing) "Refreshing" else "Refresh",
+ colorFilter = ColorFilter.tint(ColorProvider(Color(0x99FFFFFF))),
+ modifier = GlanceModifier.size(14.dp)
+ )
+ }
+}
+
+@Composable
fun HourRow(
hour: Int,
nowZoned: ZonedDateTime,
diff --git a/android/app/src/main/java/org/terst/doot/widget/work/RefreshWorker.kt b/android/app/src/main/java/org/terst/doot/widget/work/RefreshWorker.kt
index 5c0e89c..3bb8bdd 100644
--- a/android/app/src/main/java/org/terst/doot/widget/work/RefreshWorker.kt
+++ b/android/app/src/main/java/org/terst/doot/widget/work/RefreshWorker.kt
@@ -1,6 +1,7 @@
package org.terst.doot.widget.work
import android.content.Context
+import androidx.datastore.preferences.core.edit
import androidx.glance.appwidget.updateAll
import androidx.work.*
import kotlinx.coroutines.flow.first
@@ -14,16 +15,20 @@ class RefreshWorker(context: Context, params: WorkerParameters) :
CoroutineWorker(context, params) {
override suspend fun doWork(): Result {
+ val result = performRefresh()
+ applicationContext.dataStore.edit { it[Keys.IS_REFRESHING] = false }
+ DootWidget().updateAll(applicationContext)
+ return result
+ }
+
+ private suspend fun performRefresh(): Result {
val prefs = applicationContext.dataStore.data.first()
val url = prefs[Keys.SERVER_URL]?.takeIf { it.isNotBlank() } ?: return Result.failure()
val token = prefs[Keys.TOKEN]?.takeIf { it.isNotBlank() } ?: return Result.failure()
val repo = WidgetRepository(okhttp3.OkHttpClient(), url, token)
return repo.fetchAndPersist(applicationContext).fold(
- onSuccess = {
- DootWidget().updateAll(applicationContext)
- Result.success()
- },
+ onSuccess = { Result.success() },
onFailure = { Result.retry() }
)
}