From 324de612388db84616fc7a63481470ca5239d98b Mon Sep 17 00:00:00 2001 From: uvtqt Date: Tue, 10 Nov 2026 19:59:44 +0100 Subject: [PATCH] Ask for the band through the day on an empty daytime metric A metric with no history at all showed "Wear the band overnight to start the series" whatever the metric was. Right for resting heart rate, HRV or sleep; wrong for steps, active energy, strain, heart effort, movement minutes and wear time, which come from the day. Those keys (kDaytimeMetricKeys) now get the strain screen's existing "Wear the band through the day" (dayStrainWearBandFix, already translated in every locale), so no new string. Seen on the Steps screen of a fresh install on an Android emulator. --- lib/ui2/screens/metric_detail.dart | 19 +++++++++-- test/metric_detail_empty_hint_test.dart | 42 +++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 2 deletions(-) create mode 100644 test/metric_detail_empty_hint_test.dart diff --git a/lib/ui2/screens/metric_detail.dart b/lib/ui2/screens/metric_detail.dart index 4717d6ce0..b82a9d1e8 100644 --- a/lib/ui2/screens/metric_detail.dart +++ b/lib/ui2/screens/metric_detail.dart @@ -56,6 +56,18 @@ String nounInSentence(AppLocalizations? l, String name) { return '${name[0].toLowerCase()}${name.substring(1)}'; } +/// Metrics a day's wear produces, not a night's. Their empty state asks for +/// the band through the day; "overnight" would send someone to bed to get a +/// step count. +const kDaytimeMetricKeys = { + 'steps', + 'calories', + 'strain', + 'trimp', + 'active_min', + 'wear', +}; + /// What a metric key means on screen, and whether we are willing to draw it. class MetricSpec { /// The alias `getChart` / `getTrend` understand (`_trendKey` maps it on). @@ -956,8 +968,11 @@ class _MetricDetailState extends State { // them to wear the band is a promise that cannot change anything — // they already did, and the days are one tab away. fix: all.isEmpty - ? (l?.metricDetailWearBandFix ?? - 'Wear the band overnight to start the series') + ? (kDaytimeMetricKeys.contains(widget.metricKey) + ? (l?.dayStrainWearBandFix ?? + 'Wear the band through the day') + : (l?.metricDetailWearBandFix ?? + 'Wear the band overnight to start the series')) : '', icon: spec.icon, ), diff --git a/test/metric_detail_empty_hint_test.dart b/test/metric_detail_empty_hint_test.dart new file mode 100644 index 000000000..8e6fd613a --- /dev/null +++ b/test/metric_detail_empty_hint_test.dart @@ -0,0 +1,42 @@ +// A metric with no history at all tells the user what to do about it. Every +// metric used to say "Wear the band overnight to start the series", which is +// right for resting heart rate or sleep and wrong for a step count: steps, +// energy, strain and wear come from the day. Those now say "Wear the band +// through the day" (the strain screen's existing, translated hint). + +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:openstrap_edge/ui2/screens/screens.dart'; +import 'package:openstrap_edge/ui2/ui2.dart'; + +Future _pump(WidgetTester t, String key) async { + t.view.physicalSize = const Size(390 * 3, 1600 * 3); + t.view.devicePixelRatio = 3; + addTearDown(t.view.reset); + await t.pumpWidget(MaterialApp( + theme: buildTheme(Brightness.light), + home: Scaffold(body: MetricDetail(key, data: MetricData())), + )); + await t.pumpAndSettle(); +} + +const _overnight = 'Wear the band overnight to start the series'; +const _daytime = 'Wear the band through the day'; + +void main() { + for (final key in kDaytimeMetricKeys) { + testWidgets('$key, never recorded: wear it through the day', (t) async { + await _pump(t, key); + expect(find.text(_daytime), findsOneWidget); + expect(find.text(_overnight), findsNothing); + }); + } + + for (final key in ['resting_hr', 'hrv', 'sleep']) { + testWidgets('$key, never recorded: still overnight', (t) async { + await _pump(t, key); + expect(find.text(_overnight), findsOneWidget); + expect(find.text(_daytime), findsNothing); + }); + } +}