Activity: stack dots that overlap on the day timeline #314
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Follow-up of #277 (open question 4, left out of scope there).
On the day timeline of an activity command (Android,
ui/ActivityChart.kt/ui/Activity.kt), every shard is a dot on its series' lane at its time. Labels of dots less than 150 minutes apart already alternate above and below the line, but dots only minutes apart still draw on top of each other, and three or more close labels still collide.Idea
Stack colliding dots vertically within their lane (or offset them), so each event stays visible and tappable, and lay out their time labels so none overlap.
To decide
Done when
Implementation plan
Decided in refinement (supersedes the "To decide" list above):
06:40–06:52). The lane height stays fixed (64 dp), so no cap or "+N" is needed.ActivityActions.onOpen(file, line), as a row of Latest shards does). A cluster opens a menu of its shards (06:40 · titleper row); choosing one opens that note.This is app-only (Android). The core and the bindings already deliver every event of the day (
activityViewloads them all forActivityShape.DAY), each withtime,file,lineandtitle.1. Pure layout:
ui/ActivityChart.ktReplace
timelineLabels(times)(the fixed 150-minute rule) with a layout that works in dp:x = width * secondOfDay / 86400.xis less thantargetfrom the cluster's last event (chained, so a run of close events becomes one cluster). The cluster'sxis the midpoint of its first and last event (or the mean; take the midpoint, so the span label is centred).HH:mm(~labeldp wide); a cluster's label isHH:mm–HH:mm, about twice that. Alternate a cluster's label below when its label would overlap the previous cluster's label on the same side (by their widths at theirx, clamped to the lane as now). Otherwise put it above. This replaces the 150-minute rule with one that holds at every width.ActivityChartTest(replacing the test oftimelineLabels):2. Drawing:
ActivityTimelineinui/Activity.ktonOpen(passactions.onOpenfrom theActivityShape.DAYbranch).BoxWithConstraintswithmaxWidth.value.StreamdTheme.mono, 10 sp,onPrimary-like contrast: pick white or black by the colour's luminance, or draw the count beside it if that is simpler and still readable in light and dark).StreamdTheme.mono, 10 sp,offsetbybelow), with the span text for clusters.Boxof 48 dp per cluster, centred at itsxon the lane's centre line,clickable. A single dot callsonOpen(file, line). A cluster opens its menu. The semantics move from the label to this box:"<series> 06:45 <title>"for one,"<series> 3 shards 06:40–06:52"for a cluster (a new plural string resource).Surfacein the content, not a platform popup; see AGENTS.md: layoutlib renders no popup at frame 0), anchored below the tapped cluster and clamped to the screen. One row per shard,06:40 · title(title ellipsized to one line). A row callsonOpen. Tapping outside or Back closes it. The open cluster is state ofActivityContent(series index + first time,rememberSaveableas strings), passed in, so a screenshot test can draw it open.3. Tests
ActivityChartTestas listed in step 1.ActivityScreenshots.kt): add a day scene with events minutes apart in one lane (e.g. 06:40, 06:45, 06:52 and 18:30 in Run, with Climbing elsewhere) so a cluster and a single dot are both drawn. Add a second scene with that cluster's menu open. Record withupdateDebugScreenshotTest, look at every changed image (the existing day scene changes only if its events now merge), and commit them.4. Docs
REQUIREMENTS.mdR36 (Android activity screen): replace "labels less than 150 minutes apart alternate above/below" with the cluster rule: merged by touch-target distance at the current width, the count and span shown, labels alternate where they would collide, a dot opens its note, and a cluster opens a menu of its shards.README.md(activity screen paragraph): the same in user words.AGENTS.md(Android activity screen bullet):timelineClustersreplaces the label alternation, and the cluster menu is aSurfaceoverlay for layoutlib.Done when
nix build .#streamd-appandnix flake checkpass.Implementation note
Implemented in PR #321 (branch
314_stack-close-activity-dots).Findings
zIndexand unbounded in height (the 64 dp lane first cut it to one row). Taps outside it are caught by a pointer handler on the screen in the initial pass and consumed, since no scrim can lie between the menu and the scrolling content. The tap-outside path is only covered by reading the code. It was not tried on a device or emulator.