Water intake tracking for Android — a quick-add widget, streaks, and Health Connect sync.
Long gap since the last post — this is everything interesting since then, which is really one thing: I redid how reminders get scheduled.
They were running on WorkManager, a OneTimeWorkRequest that re-enqueues itself. Worked in testing, then I left the phone alone for a while and reminders started landing whenever, not on the interval I’d set. Turns out that’s just what WorkManager is — “run this eventually, respecting Doze/battery constraints,” not “run this at 2:00pm.” setExpedited doesn’t fix that.
Switched to AlarmManager.setWindow() plus a plain broadcast receiver instead. One alarm at a time, five-minute flex, and I compute the next trigger time myself rather than trusting a work chain — before the window, target start time; after it, roll to tomorrow; inside it, round up to the next interval and clamp to the end. Had to actually think through those edge cases instead of hand-waving them.
The receiver shows the notification if we’re still inside today’s window when it fires, then immediately schedules the next one. Also added a BootReceiver, since alarms don’t survive a reboot the way a WorkManager chain sort of does for free — now I own that instead.
Trade-off’s real, but reminders land within ~5 minutes of when they should now instead of “eventually.” Health Connect sync went in right after this too (just permissions/plumbing, nothing syncing yet) — probably the next one.
Made a Wear OS module. It does not talk to the phone yet. Set up a WearableListenerService and a message client on the phone side to push intake updates over — Wearable.getNodeClient(...).connectedNodes, straightforward on paper — but the actual round trip never worked in this pass. Leaving the plumbing in since the shape is probably right, just didn’t get far enough to prove it.
Also, unrelated but landed in the same window: the whole app is translatable now (English + Serbian Latin), and the widget click opens the app directly instead of going through the animation first.
Spent two weeks fighting the widget. First pass was a classic XML AppWidgetProvider — RemoteViews, the whole deal. Got it on the home screen, clicking it opened the app, fine. Then I wanted the click to work even when the app wasn’t already running and the XML approach turned into a mess of edge cases, so I ripped it out (XMLWaterIntakeWidgetProvider gone) and just… didn’t have a widget for a few days while I cleaned up everything else — removed a bunch of Context passing I didn’t need, redid the color scheme, let auto-refactor loose on the whole codebase.
In the middle of that I also got the graph working (past week only for now), paging on the intake list, and notifications actually firing for the first time (“Notifications WORK!!!” — commit message not lying, that was a good moment).
Widget came back a few days later as a Jetpack Glance widget instead of raw RemoteViews — much less fighting the platform, though my first version of it was, in my own words at the time, “ugly as hell.” Took one more pass after that to make it look decent. So: three different widget implementations before landing on the one that’s still in the app now.
I keep forgetting to drink water, so I’m building an app that nags me about it. Nothing clever yet — Room DB for logging intake, a top bar, a slideout nav, a home screen that’s actually starting to look like something. Threw together a widget too but it doesn’t work at all yet, just screens and todos wired up so I remember what’s left. First commit was literally empty scaffolding, this is the first bit of it that does anything.