Skip to Content
FeaturesDashboardToday widget

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: Added glance-appwidget = "1.1.0" version
  • composeApp/build.gradle.kts: Added implementation(libs.glance.appwidget) dependency

2. Shared Models (KMP)

  • shared/src/commonMain/kotlin/com/esteban/ruano/oter/models/widget/TodayActionItem.kt
    • Sealed interface TodayActionItem with id and title
    • TodayTaskItem: Task-specific data (isCompleted, priority, dueDateTime)
    • TodayHabitItem: Habit-specific data (todayDone, streak, frequency)

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

4. Widget Implementation (Android)

  • composeApp/src/androidMain/kotlin/com/esteban/ruano/oter/widget/OterTodayWidget.kt

    • OterTodayWidget: Main widget class extending GlanceAppWidget
    • OterTodayWidgetContent: Composable UI for the widget
    • ActionItemRow: Individual action item display
    • refreshOterTodayWidget(): 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.kt

    • OterTodayWidgetReceiver: Broadcast receiver for widget lifecycle events

5. Dependency Injection

  • composeApp/src/androidMain/kotlin/com/esteban/ruano/oter/di/WidgetModule.kt
    • Provides GetTasksWithSmartFiltering and GetHabitsByRangeDate at Singleton scope
    • Provides GetTodayActionsUseCase for widget use

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_description string resource

7. Manifest Registration

  • composeApp/src/androidMain/AndroidManifest.xml
    • Registered OterTodayWidgetReceiver with APPWIDGET_UPDATE intent filter
    • Linked to widget info XML via meta-data

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

  1. 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
  2. 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
  3. Interaction:

    • Tapping anywhere on the widget opens MainActivity

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) }

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:

  • TasksViewModel after completeTask/unCompleteTask
  • HabitsViewModel after completeHabit/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

  1. Build and install the app
  2. Long-press on home screen → Widgets
  3. Find “Oter – Today’s Actions” in the widget picker
  4. Add to home screen
  5. Verify it shows today’s tasks and habits
  6. 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