Oter Today Widget Implementation
Implementation guide for the Jetpack Glance home-screen widget that displays today’s tasks and habits.
Overview
A Jetpack Glance home-screen widget that displays today’s tasks and habits in a unified list. The widget shows up to 6 items and opens the main app when tapped.
Files Created/Modified
1. Dependencies
gradle/libs.versions.toml: Addedglance-appwidget = "1.1.0"versioncomposeApp/build.gradle.kts: Addedimplementation(libs.glance.appwidget)dependency
2. Shared Models (KMP)
shared/src/commonMain/kotlin/com/esteban/ruano/oter/models/widget/TodayActionItem.kt- Sealed interface
TodayActionItemwithidandtitle TodayTaskItem: Task-specific data (isCompleted, priority, dueDateTime)TodayHabitItem: Habit-specific data (todayDone, streak, frequency)
- Sealed interface
3. Shared Use Case (KMP)
shared/src/commonMain/kotlin/com/esteban/ruano/oter/domain/use_case/widget/GetTodayActionsUseCase.kt- Fetches today’s tasks using
GetTasksWithSmartFiltering - Fetches today’s habits using
GetHabitsByRangeDate - Combines and sorts them (incomplete items first, by priority/streak)
- Filters habits based on frequency to show only relevant ones for today
- Fetches today’s tasks using
4. Widget Implementation (Android)
-
composeApp/src/androidMain/kotlin/com/esteban/ruano/oter/widget/OterTodayWidget.ktOterTodayWidget: Main widget class extendingGlanceAppWidgetOterTodayWidgetContent: Composable UI for the widgetActionItemRow: Individual action item displayrefreshOterTodayWidget(): Helper function to refresh the widget- Uses Hilt EntryPoint to access dependencies (widgets can’t use @AndroidEntryPoint)
-
composeApp/src/androidMain/kotlin/com/esteban/ruano/oter/widget/OterTodayWidgetReceiver.ktOterTodayWidgetReceiver: Broadcast receiver for widget lifecycle events
5. Dependency Injection
composeApp/src/androidMain/kotlin/com/esteban/ruano/oter/di/WidgetModule.kt- Provides
GetTasksWithSmartFilteringandGetHabitsByRangeDateat Singleton scope - Provides
GetTodayActionsUseCasefor widget use
- Provides
6. Configuration Files
-
composeApp/src/androidMain/res/xml/oter_today_widget_info.xml- Widget configuration (size, resize mode, update period, etc.)
- Configured as a 2x2 cell widget, resizable horizontally and vertically
-
composeApp/src/androidMain/res/layout/glance_default_loading_layout.xml- Loading placeholder layout shown while widget initializes
-
composeApp/src/androidMain/res/values/strings.xml- Added
widget_today_actions_descriptionstring resource
- Added
7. Manifest Registration
composeApp/src/androidMain/AndroidManifest.xml- Registered
OterTodayWidgetReceiverwithAPPWIDGET_UPDATEintent filter - Linked to widget info XML via meta-data
- Registered
Architecture
Widget data flow: the receiver triggers the widget, which uses a Hilt EntryPoint to access the shared KMP use case, then renders up to 6 items via Glance.
How It Works
-
Data Fetching: When the widget needs to update, it:
- Uses Hilt EntryPoint to get
GetTodayActionsUseCase - Fetches today’s tasks and habits in parallel
- Combines them into a unified list
- Sorts by completion status and priority/streak
- Uses Hilt EntryPoint to get
-
UI Display:
- Shows “Today’s Actions” title
- Displays up to 6 items
- Each item shows:
- Task: ✅ (completed) or ⬜ (pending) + title
- Habit: ✅ (done today) or 🔁 (pending) + title + 🔥 streak
- Shows “Nothing pending 🎉” if no actions
-
Interaction:
- Tapping anywhere on the widget opens
MainActivity
- Tapping anywhere on the widget opens
Usage
Refreshing the Widget
To refresh the widget after completing/uncompleting a task or habit, call:
import com.esteban.ruano.oter.widget.refreshOterTodayWidget
// In a coroutine scope
lifecycleScope.launch {
refreshOterTodayWidget(context)
}Recommended Refresh Points
Add widget refresh calls in:
- After marking a task as complete/incomplete
- After marking a habit as done/undone
- After creating a new task/habit
- Optionally: From a WorkManager job scheduled at midnight or periodically
TODO: Add refresh calls in:
TasksViewModelaftercompleteTask/unCompleteTaskHabitsViewModelaftercompleteHabit/unCompleteHabit- Any screen that creates/updates tasks or habits
Widget Features
- Dark Theme: Uses dark background (#1E1E1E) with white text
- Responsive: Resizable horizontally and vertically
- Smart Filtering: Only shows habits that should appear today based on frequency
- Sorted Display: Incomplete items first, sorted by priority (tasks) or streak (habits)
- Error Handling: Gracefully handles errors (shows empty list if data fetch fails)
Testing
- Build and install the app
- Long-press on home screen → Widgets
- Find “Oter – Today’s Actions” in the widget picker
- Add to home screen
- Verify it shows today’s tasks and habits
- Tap the widget to verify it opens the app
Notes
- Widget updates are manual (no automatic periodic updates)
- The widget fetches data each time it’s displayed/updated
- For better performance, consider caching results (TODO)
- The widget uses the same date format (DD/MM/YYYY) as the rest of the app
- Habit frequency filtering is simplified - for more accurate logic, use the habit’s
nextOccurrence()method