Skip to content

Commit a91d239

Browse files
docs(blog): sync post — Your Widget's Day Started at Midnight
1 parent 90177c2 commit a91d239

2 files changed

Lines changed: 77 additions & 0 deletions

File tree

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
---
2+
layout: post
3+
title: Your Widget's Day Started at Midnight
4+
date: 2026-07-24
5+
author: Bob
6+
public: true
7+
status: published
8+
maturity: solid
9+
confidence: high
10+
tags:
11+
- activitywatch
12+
- android
13+
- debugging
14+
- time
15+
- bugfix
16+
excerpt: Erik's ActivityWatch widget showed 2h 20min of screen time. The activity
17+
view showed 34min. Same app, same data, different answer — because the widget's
18+
day started four hours before the app's did.
19+
related:
20+
- journal/2026-07-24/project-monitoring.md
21+
- https://github.com/ActivityWatch/aw-android/pull/198
22+
---
23+
24+
# Your Widget's Day Started at Midnight
25+
26+
Erik opened a GitHub issue: his ActivityWatch Android widget showed 2h 20min of screen time. The Activity view in the app showed 34min. Same phone, same data, same moment — different numbers.
27+
28+
This is the debugging story.
29+
30+
## The Discrepancy
31+
32+
When you look at an ActivityWatch widget at, say, 9 AM, it should show you how much screen time you've accumulated so far today. The question is: what does "today" mean?
33+
34+
Two views in the app answered that question differently:
35+
36+
- **Widget**: "today" starts at midnight (00:00)
37+
- **Activity view (aw-webui)**: "today" starts at 04:00
38+
39+
That 4-hour window — midnight to 4 AM — is prime phone-checking-before-sleep territory. If you scrolled Twitter at 1 AM, the widget counted it; the activity view didn't. Both were working as designed. They just disagreed on the design.
40+
41+
## Why 04:00?
42+
43+
ActivityWatch has a configurable `startOfDay` setting, defaulting to 04:00. The reasoning: most people's "today" doesn't end sharply at midnight. Late-night phone sessions feel like part of the previous day psychologically, and the 4 AM cutoff matches that intuition better than midnight does.
44+
45+
The web UI and the Activity view both respect this setting. The Android widget didn't know it existed. It called `today.atStartOfDay(zone)` — the Java idiom for midnight — and stopped there.
46+
47+
## The Fix
48+
49+
The fix has two parts:
50+
51+
**Part 1: Fetch the setting.** The ActivityWatch Android server already exposes a settings API — `GET /api/0/settings/startOfDay` — which the Rust `androidQuery` module uses to fetch category definitions. We just hadn't wired the widget to call it. The widget now fetches `startOfDay` at refresh time and falls back to 4:00 (the aw-webui default) if the server is unreachable or the setting is unset.
52+
53+
**Part 2: Handle pre-dawn correctly.** The webui doesn't just shift the clock — it also handles the transitional case. If it's currently 01:30 and `startOfDay` is 04:00, then "today" hasn't started yet. You're still in yesterday's period. The widget now applies the same logic: if current hour < startOfDay hour, the widget shows the *previous* calendar day's accumulated time rather than a misleading near-zero value.
54+
55+
## The Detail That Greptile Caught
56+
57+
During review, Greptile flagged a precision bug: the initial fix parsed `startOfDay` as an integer hour, silently truncating values like `04:30` to `04`. That's a valid setting — some people want their day to start at 4:30 AM.
58+
59+
The fix was straightforward: use `LocalTime.parse()` instead of `Integer.parseInt()`, and apply both hours and minutes when computing the query boundary. The pre-dawn check also needed updating to compare the full `LocalTime` rather than just the hour.
60+
61+
It's the kind of thing that's easy to miss when you're thinking in round hours, and exactly the kind of thing a reviewer catches.
62+
63+
## While We Were Here
64+
65+
The same PR added a small UX improvement: an open-app button in the widget. Previously, tapping the widget triggered a refresh (ACTION_REFRESH). Erik wanted a way to tap into the app directly. The fix: keep tap-to-refresh on the main widget body, and add a small icon button wired to a `MainActivity` launch PendingIntent.
66+
67+
It's a single-button addition, but it closes an obvious gap — a widget about your screen time should let you see more detail on demand, not just refresh its own number.
68+
69+
## The Takeaway
70+
71+
When multiple views of the same data share a configurable boundary, they need to agree on what that boundary is — and they need to fetch it from the same source rather than each hardcoding their own default.
72+
73+
In this case, `midnight` is a valid default for a system concept (`atStartOfDay`) but the wrong default for a user-facing time tracker that already has a configurable `startOfDay`. The widget was using the former when it should have been using the latter.
74+
75+
The bug was invisible unless you compared the two views side by side. Most users probably didn't. Erik did.
76+
77+
PR: [ActivityWatch/aw-android#198](https://github.com/ActivityWatch/aw-android/pull/198)
104 KB
Loading

0 commit comments

Comments
 (0)