Track walks as timed exercise
A walk is a start and an end, so it reuses the shape sleep already has rather than inventing one: walk-start / walk-end events, paired into windows, with a trailing unmatched start meaning "out right now". The server stores type as an opaque string, so nothing there changes and the events ride the existing sync. Pairing boundaries into windows was written out twice already, once for sleep and once for its inverse, so this pulls the scan into pairWindows(open, close) and makes all three callers of it. Same for the latest-boundary lookup behind currentSleepState, which currentWalkState now shares — including the updatedAt tie-break, which matters as soon as a start and an end land in the same minute. They are called walks, not exercise. "Exercise" is already taken by the training definitions (their own synced collection, and exerciseId on training events), and two meanings of the word in one app would be worse than the slightly narrower name. The day's total leads the overview tile with the count underneath, since the question is how much exercise the puppy got rather than how many outings it took. The Walks panel lists the day's windows and carries the total in its heading so a collapsed panel still answers it, and the daily charts gain a minutes-per-day bar chart that stays hidden until there is a walk to draw — the grams chart's rule. The panel also states the five-minute rule for the puppy's current age, the same way the sleep trend states a goal band. Walk boundaries answer to the walk state, not the sleep one, so "Walk end" is disabled with no walk running and stays undimmed mid-walk even while the puppy is logged asleep.
This commit is contained in:
+25
-2
@@ -111,14 +111,18 @@
|
||||
<!-- Explicit rows, grouped by what the buttons mean, rather than one
|
||||
auto-fit grid: a start/end pair has to stay side by side at every
|
||||
width (a flat grid split them apart at some column counts, and
|
||||
orphaned the last button on a row of its own). Row 1 is the timed
|
||||
pair, row 2 the one-tap moments, row 3 the two that open a dialog
|
||||
orphaned the last button on a row of its own). A row per timed
|
||||
pair, then the one-tap moments, then the two that open a dialog
|
||||
to type a value. -->
|
||||
<div class="actions">
|
||||
<div class="action-row">
|
||||
<button class="action sleep" data-type="sleep-start">😴 Sleep start</button>
|
||||
<button class="action sleep" data-type="sleep-end">⏰ Sleep end</button>
|
||||
</div>
|
||||
<div class="action-row">
|
||||
<button class="action walk" data-type="walk-start">🦮 Walk start</button>
|
||||
<button class="action walk" data-type="walk-end">🏁 Walk end</button>
|
||||
</div>
|
||||
<div class="action-row three-up">
|
||||
<button class="action eat" data-type="eat">🍽️ Ate</button>
|
||||
<button class="action pee" data-type="pee">💧 Pee</button>
|
||||
@@ -154,6 +158,11 @@
|
||||
<div class="stat-label">Awake</div>
|
||||
<div class="stat-value" id="stat-awake">0h 0m</div>
|
||||
</div>
|
||||
<div class="stat">
|
||||
<div class="stat-label">Walks</div>
|
||||
<div class="stat-value" id="stat-walk">0m</div>
|
||||
<div class="stat-sub" id="stat-walk-count" hidden></div>
|
||||
</div>
|
||||
<div class="stat">
|
||||
<div class="stat-label">Meals</div>
|
||||
<div class="stat-value" id="stat-meals">0</div>
|
||||
@@ -178,6 +187,7 @@
|
||||
<div class="last-row"><span>Last poo</span><span id="last-poo">—</span></div>
|
||||
<div class="last-row"><span>Last meal</span><span id="last-eat">—</span></div>
|
||||
<div class="last-row"><span>Last sleep</span><span id="last-sleep">—</span></div>
|
||||
<div class="last-row"><span>Last walk</span><span id="last-walk">—</span></div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -221,6 +231,15 @@
|
||||
<p id="wake-empty" class="empty">No wake windows yet for this day.</p>
|
||||
</section>
|
||||
|
||||
<section class="walks" data-panel="walks">
|
||||
<h2>Walks <span class="muted-note" id="walk-total"></span></h2>
|
||||
<ul id="walk-list" class="wake-list"></ul>
|
||||
<p id="walk-empty" class="empty">No walks yet for this day. Use 🦮 Walk start / 🏁 Walk end to time one.</p>
|
||||
<!-- Age-based guidance ("the five-minute rule"), only when a birthday
|
||||
is set and the puppy is still growing. -->
|
||||
<p id="walk-goal" class="muted-note" hidden></p>
|
||||
</section>
|
||||
|
||||
<section class="weekly" data-panel="weekly">
|
||||
<h2 id="daily-charts-title">Last 7 days</h2>
|
||||
<div class="chart-days-picker" role="group" aria-label="How many days the charts cover">
|
||||
@@ -241,6 +260,10 @@
|
||||
<label class="lg eat"><input type="checkbox" data-metric="meals" checked /><span class="sw"></span>Meals</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="chart" id="walk-chart-wrap" hidden>
|
||||
<div class="chart-title">Walks (minutes)</div>
|
||||
<svg id="chart-walk" class="chart-svg" viewBox="0 0 320 160" role="img" aria-label="Minutes walked per day"></svg>
|
||||
</div>
|
||||
<div class="chart" id="grams-chart-wrap" hidden>
|
||||
<div class="chart-title">Food (grams)</div>
|
||||
<svg id="chart-grams" class="chart-svg" viewBox="0 0 320 160" role="img" aria-label="Grams of food eaten per day"></svg>
|
||||
|
||||
Reference in New Issue
Block a user