Consolidate 4 widget variants into single receiver with config activity - #298
Conversation
Replaced 4 separate GlanceAppWidgetReceiver classes (and their matching XML provider files and manifest entries) with a single MensinatorWidgetReceiver. Added WidgetConfigActivity so users choose their preferred design (label/no label, background/no background) when adding the widget, with the choice stored per instance in Glance Preferences state. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Revert to 4 separate receivers so all 4 designs appear directly in the widget picker (no config activity needed) - Each receiver's BaseWidget instance now calls providePreview() with its own showLabel/showBackground so Android 15+ shows the correct visual preview per design in the picker - Fix cramped appearance: replace top-aligned LazyColumn in the label variant with a centred Box; increase number text size to 24sp in the no-label variant; set targetCellWidth/Height in all XML providers so Android places label widgets at 2x1 and compact widgets at 1x1 by default - Remove WidgetConfigActivity (no longer needed) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
Addressed the feedback in the latest commit:
|
setWidgetPreviews() only renders live previews on Android 15+. Add android:previewLayout to all 4 providers with RemoteViews approximation layouts so the picker shows each design's appearance on Android 12-14 (API 31+), covering devices like the Galaxy S23. - 4 preview layouts mirroring each design (label/no-label x bg/no-bg) - Rounded solid background drawable for the no-background variants - Preview-only sample strings Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
| <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" | ||
| android:layout_width="match_parent" | ||
| android:layout_height="match_parent" | ||
| android:background="@drawable/widget_background" |
| <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" | ||
| android:layout_width="match_parent" | ||
| android:layout_height="match_parent" | ||
| android:background="@drawable/widget_background"> |
| <string name="widget_period_abbreviation">P</string> | ||
| <string name="widget_ovulation_abbreviation">O</string> | ||
| <!-- Sample values shown only in the widget picker preview --> | ||
| <string name="widget_preview_sample_number">10</string> |
| <string name="widget_ovulation_abbreviation">O</string> | ||
| <!-- Sample values shown only in the widget picker preview --> | ||
| <string name="widget_preview_sample_number">10</string> | ||
| <string name="widget_preview_sample_with_label">Period in 10 days</string> |
| android:minHeight="50dp" | ||
| android:minWidth="110dp" | ||
| android:minHeight="40dp" | ||
| android:targetCellWidth="2" |
| android:minWidth="73dp" | ||
| android:minHeight="73dp" | ||
| android:targetCellWidth="1" | ||
| android:targetCellHeight="1" |
| android:minHeight="73dp" | ||
| android:targetCellWidth="1" | ||
| android:targetCellHeight="1" | ||
| android:previewLayout="@layout/widget_preview_without_label_with_bg" |
| android:minHeight="50dp" | ||
| android:minWidth="73dp" | ||
| android:minHeight="73dp" | ||
| android:targetCellWidth="1" |
| android:minWidth="73dp" | ||
| android:minHeight="73dp" | ||
| android:targetCellWidth="1" | ||
| android:targetCellHeight="1" |
| android:minHeight="73dp" | ||
| android:targetCellWidth="1" | ||
| android:targetCellHeight="1" | ||
| android:previewLayout="@layout/widget_preview_without_label_no_bg" |
minHeight=73dp pushed the compact widgets into 2 rows in the picker on a standard launcher grid. Lower it to 40dp so the targetCellHeight=1 hint is honoured and the no-label designs occupy a single 1x1 cell, matching the maintainer's expected layout. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds a simulated "day offset" so the widget countdown can be advanced for testing without altering the device clock (which disrupts alarms, notifications, etc.). - WidgetDebugDayShift: stores an int offset in SharedPreferences and exposes today() = now + offset. Entirely gated behind BuildConfig.DEBUG, so in release builds the offset is always 0 and widgets are unaffected. - BaseWidget: computes days-until-period from WidgetDebugDayShift.today(). - SettingsScreen: a Debug section (-1 / +1 / Reset) shown only in debug builds; changing the offset persists it and refreshes all widgets. - Enable buildConfig feature so BuildConfig.DEBUG is available. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
Pushed two more commits, verified on an Android 14 emulator: 1. Compact widgets are now 1×1 ( 2. New: debug-only widget day-shift ( What it doesLets you simulate the day rolling over to test the widget countdown without changing the device's system clock (which otherwise messes with alarms, notifications, and other time-based logic). How it works
Release safetyThe whole thing is gated behind
(This required enabling the |
All four designs were instances of the same concrete BaseWidget class. Glance resolves which widgets to refresh in updateAll() by the GlanceAppWidget's concrete class, so a single shared class made that lookup ambiguous: - Debug day-shift (and any refresh) only updated one design's widgets. - On app start the four concurrent updateAll() calls raced and re-rendered every placed widget with whichever instance won, so designs stomped each other (e.g. a 2x1 label widget rendered as a no-label one, losing its text). The race made it intermittent. Make BaseWidget abstract and add one concrete subclass per design, so each receiver maps to a distinct GlanceAppWidget class and updateAll() resolves the correct widget instances. Also guard formatDaysUntilPeriod(): until() was called before the null check, so a fresh install with no tracked period threw NullPointerException and the widget showed "Can't show content". Now it renders "?"/"Unknown" instead. Verified on an Android 14 emulator with two different designs placed: +1 in the debug panel updates both widgets together (11 -> 10), and five app restarts keep each design intact with no missing text. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
Fixed both reported issues — they turned out to share one root cause. Verified end-to-end on an Android 14 emulator with two different designs placed on the home screen. Root cause: all four designs were instances of the same
Fix: Also fixed a crash found while testing: Verification (offset starts at 0, next period 11 days out):
|


Summary
GlanceAppWidgetReceiverclasses (WidgetPeriodDaysWithLabel*,WidgetPeriodDaysWithoutLabel*) with a singleMensinatorWidgetReceivermensinator_widget_provider2/3/4.xml) — they were identical except for the description stringWidgetConfigActivity: when the user adds the widget, Android opens this screen so they can choose their preferred design (with/without label × with/without background)SHOW_LABEL,SHOW_BACKGROUNDkeys), read directly byBaseWidgetat render timeBootReceiver,MidnightWorker,PeriodCalculationWidgetUpdater,MainActivity) from iterating a list of 4 receivers to a singleBaseWidget().updateAll(context)callWidgetModuleKoin module since receiver instances no longer need to be managed by DITest plan
WidgetConfigActivityshould appear with 4 design options🤖 Generated with Claude Code