Last active
December 30, 2023 12:45
-
-
Save kishan-vadoliya/229b3f61c6408ebdeb98f15c52bb8567 to your computer and use it in GitHub Desktop.
Android App Widget Development with Glance
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// https://medium.com/atlas/android-app-widget-development-with-glance-532a5a8d602c | |
// User Interface | |
<!-- API 31 (Android 12 and up) --> | |
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" | |
android:description="@string/widget_description" | |
android:minWidth="200dp" | |
android:minHeight="200dp" | |
android:resizeMode="horizontal|vertical" | |
android:previewImage="@drawable/calendar_widget_preview_image" | |
android:previewLayout="@layout/calendar_widget_small_layout" | |
android:targetCellWidth="2" | |
android:targetCellHeight="3" | |
android:maxResizeWidth="300dp" | |
android:maxResizeHeight="600dp" | |
android:widgetCategory="home_screen" | |
android:updatePeriodMillis="0" | |
/> | |
Column( | |
modifier = GlanceModifier.padding(all = 2.dp).fillMaxWidth().background(Color.White), | |
horizontalAlignment = Alignment.CenterHorizontally | |
) { | |
// UP/Prev button | |
Image( | |
provider = ImageProvider(com.bottlerocket.android.consolidator.R.drawable.ic_arrow_up_24), | |
contentDescription = "Back", | |
modifier = GlanceModifier.defaultWeight() | |
.background(Color.Transparent) | |
.clickable(onClick = actionRunCallback<CalendarActionCallback>( | |
actionParametersOf(pairs = arrayOf(ActionParameters.Key<DateArrow>(KEY_DATE_ARROW) to DateArrow.Back))) | |
) | |
) | |
val monthEvents = calendarEventsMap.filter { it.key.year == firstMonthState.year && it.key.month == firstMonthState.month } | |
MonthCalendarWidgetUI(firstMonthState, monthEvents) | |
if (numMonthsToShow >= 2) { | |
val secondMonth = firstMonthState.plusMonths(1) | |
val secondMonthEvents = calendarEventsMap.filter { it.key.year == secondMonth.year && it.key.month == secondMonth.month } | |
MonthCalendarWidgetUI(secondMonth, secondMonthEvents) | |
} | |
} | |
// Work Manager | |
fun startCalendarDataFetch(workManager: WorkManager) { | |
calendarWidgetLog("queueCalendarDataRequest") | |
val constraints = Constraints.Builder() | |
.setRequiredNetworkType(NetworkType.CONNECTED) | |
.setRequiresCharging(false) | |
.setRequiresBatteryNotLow(true) | |
.build() | |
// NOTE: min period is 15 minutes. | |
val request = PeriodicWorkRequestBuilder<CalendarWorkManager>( | |
Duration.ofMinutes( | |
CALENDAR_WORK_REQ_PERIOD_MINUTES | |
)) | |
.setConstraints(constraints) | |
.setInitialDelay(Duration.ofSeconds(CALENDAR_WORK_REQ_INITIAL_DELAY_SECONDS)) | |
.build() | |
// MUST: Specifying "unique" and "KEEP" will ensure there is only one worker in the system. | |
val operation = workManager.enqueueUniquePeriodicWork( | |
CALENDAR_FETCH_WORKER, | |
ExistingPeriodicWorkPolicy.KEEP, | |
request) | |
calendarWidgetLog("WorkManager queue status: ${operation.result}") | |
} | |
// | |
private suspend fun updateWidgetData(events: List<DayEvent>) { | |
GlanceAppWidgetManager(context = context).getGlanceIds(ConsolidatorAppWidget::class.java).forEach { glanceId -> | |
updateAppWidgetState(context, glanceId) { prefs -> | |
calendarWidgetLog("updateAppWidgetState: glanceId: $glanceId") | |
// Each app widget instance stores in a different DataStore file. | |
prefs.setCalendarData(events) | |
} | |
// VERY IMPORTANT: Refreshing App Widget with updated events here. | |
calendarWidgetLog("updateWidgetData: Update UI") | |
ConsolidatorAppWidget().update(context, glanceId) | |
} | |
} | |
// | |
class ConsolidatorAppWidget: GlanceAppWidget() { | |
private val isDebugOverride = false // Set to true to have only one widget size to reduce logging clutter | |
/** | |
* Used to dynamically configure Widget as user is resizing it. | |
*/ | |
override val sizeMode: SizeMode = SizeMode.Responsive( | |
if (isDebugOverride && isDebug()) setOf(ONE_MONTH_WIDGET) else setOf(ONE_MONTH_WIDGET, TWO_MONTH_WIDGET) | |
) | |
... | |
} | |
// Useful Links | |
General App Widget Documentation (Non-Glance specific) | |
Glance Overview | |
Glance Sample Code from Google | |
StackOverflow topic/tag: glance-appwidget | |
Glance Bugs List |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment