* HabitWidget.kt extends GlanceAppWidget with SizeMode.Responsive supporting three size breakpoints.
* The Content() composable reads data from currentState<Preferences>() which maps to the SharedPreferences populated by Flutter.
* HabitWidgetReceiver.kt extends GlanceAppWidgetReceiver and provides the GlanceAppWidget instance.
* ToggleHabitAction extends ActionCallback and handles toggle clicks by sending a broadcast intent to Flutter's background handler and optimistically updating SharedPreferences.
* Widget metadata is defined in res/xml/widget_info.xml with minimum and target sizes, resize mode, and preview image.
* The widget is declared in AndroidManifest.xml with the receiver, intent filter, and metadata.
* A WorkManager PeriodicWorkRequest is scheduled on app first launch (and verified on subsequent launches) to refresh widget data at midnight and every 6 hours as a fallback.
* The Glance layout uses Column, Row, Text, Image, Box, and Spacer composables with GlanceModifier for styling.
* GlanceTheme automatically adapts to the device's Material You dynamic colors.
gherkin
Given the HabitWidgetReceiver is declared in AndroidManifest
When the user navigates to the widget picker on the home screen
Then Habit appears as an available widget with a preview image
Given the widget Content composable renders
When SharedPreferences contain a score of 82 and a streak of 14
Then the widget displays "🧠 82" and "🔥 14" in the header row
Given the widget renders in large mode with 3 habits in SharedPreferences
When each habit row renders
Then it shows a checkbox visual (filled or outline), the habit name, and handles tap gestures for toggling
Given the ToggleHabitAction fires for habit "h1"
When the action callback executes
Then SharedPreferences are updated to toggle habit "h1" completion status and the widget is re-rendered immediately
Given the WorkManager midnight refresh task executes
When it runs at midnight
Then it clears the previous day's habit data from SharedPreferences and signals a widget update
Given the widget data in SharedPreferences is empty or corrupted
When the widget renders
Then it shows a graceful fallback state with the app icon and "Open HabitForge" text instead of crashing
Details and Assumptions
Acceptance Criteria