feat(alarmas): rewrite alarm editor with inline time widget

Replace the native showTimePicker dialog in the alarm editor sheet with
a giant inline HH:MM editor (drag/tap to adjust, wraps at 23:59-00:00).
Weekday circles now render unconditionally (disabled outside weekly
mode) instead of being gated behind an `if`.

The date field, fallback-station picker, and sound dropdown are not
dropped: per resolution 3 they move into a collapsed "Advanced" section
so the mockup's weekday-circles-only layout does not lose capability.
Volume/fade-in sliders get a cosmetic type-scale restyle only.

size:exception: 993 changed lines (891+/102-) against the 500-650
forecast - lib/ production code alone is 429 lines, within band; new
test files and 13 regenerated l10n/gen files account for the rest, the
same pattern every prior work unit in this branch has hit.
This commit is contained in:
2026-07-29 11:43:15 +02:00
parent 332c2192cd
commit a2121d84bd
22 changed files with 935 additions and 115 deletions
+51 -13
View File
@@ -612,22 +612,60 @@ splitting further would leave either dead query methods with no UI consumer or a
**New tests**: `test/widgets/editor_hora_inline_test.dart` (standalone)
**Modified tests**: `pantalla_alarmas_fecha_test.dart`
- [ ] 10.1 RED — `editor_hora_inline_test.dart`, **standalone, independent of the sheet**: drag/tap adjusts hour and
minute, wraps at 23:59→00:00, exposes correct a11y labels.
- [ ] 10.2 GREEN — implement `lib/widgets/editor_hora_inline.dart` (giant inline HH:MM display, drag/tap-to-adjust).
- [ ] 10.3 RED — update `pantalla_alarmas_fecha_test.dart`: one-time date alarm still creatable via the (now
- [x] 10.1 RED — `editor_hora_inline_test.dart`, **standalone, independent of the sheet**: drag/tap adjusts hour and
minute, wraps at 23:59→00:00, exposes correct a11y labels. **Correction found at apply time**: Flutter
requires a `Semantics` node exposing `onIncrease`/`onDecrease` to ALSO carry `increasedValue`/`decreasedValue`
whenever `value` is set (`SemanticsNode.updateWith`'s `(value == '') == (increasedValue == '')` assertion) —
added both, computed from the same pure delta-preview helpers the mutation uses. Also had to set
`excludeSemantics: true` on each segment's `Semantics` node: without it, the inner `GestureDetector`'s own
semantics contribution merged upward and (a) duplicated the digits into `label` via the child `Text`'s
implicit semantics and (b) auto-exposed `scrollUp`/`scrollDown` (Flutter's default accessibility mapping for
a registered vertical-drag recognizer) — neither wanted. Every action (`tap`/`increase`/`decrease`) is now
declared explicitly on the one Semantics node instead.
- [x] 10.2 GREEN — implement `lib/widgets/editor_hora_inline.dart` (giant inline HH:MM display, drag/tap-to-adjust).
Tap increments by one step (wrapping); vertical drag adjusts continuously (24px/step, chosen for a
comfortable scrub distance — not a reused measured constant, this widget has no other consumer).
- [x] 10.3 RED — update `pantalla_alarmas_fecha_test.dart`: one-time date alarm still creatable via the (now
collapsed) Advanced section; fallback-station picker and sound dropdown still settable and persisted.
- [ ] 10.4 GREEN — replace the native `showTimePicker` dialog with `EditorHoraInline`; keep weekday circles always
**Correction found at apply time**: this file previously held ONLY the 2 pure `fechaCortaLocalizada` format
tests, no widget coverage at all — extended it in place (kept both untouched) rather than creating a second
file, since the task's own instruction was to "update" this file. Also required a one-line surgical fix to
the PRE-EXISTING fallback-station test in `pantalla_alarmas_editor_test.dart` (not itself listed as a
"Modified test" for this WU): a collapsed `ExpansionTile` does not build its children, so
`find.byKey('alarm-fallback-station-field')` found nothing until the "Advanced" header is tapped first —
added that one tap, no scenario/assertion changed.
- [x] 10.4 GREEN — replace the native `showTimePicker` dialog with `EditorHoraInline`; keep weekday circles always
visible; move the date field, fallback-station picker, and sound dropdown into a collapsed "Advanced"
section rather than dropping them.
- [ ] 10.5 GREEN — restyle the volume/fade-in sliders (cosmetic only, no behaviour change).
- [ ] 10.6 REFACTOR — confirm the dismiss-guard test is untouched by this WU (editor sheet only, not the ringing
screen).
- [ ] 10.7 Verify — standalone widget test green independent of the sheet; date/fallback/sound round-trip test
green.
section rather than dropping them. **Design decision, not specified by any ADR (WU10 has none)**: the
one-time/daily/weekly `SegmentedButton` stays in the main flow (not Advanced) since it gates which weekday
circles are enabled; weekday circles now render unconditionally with `onSelected: null` (Material's standard
disabled-chip state) when `_tipo != diasSemana`, instead of being removed from the tree — no change to
`_tipo`/`diasSemana`/`fechaUnica` persistence logic, confirmed the scheduler treats `diaria` and
`diasSemana` as genuinely different code paths (`_buscarDiaria` vs `_buscarPorDiasSemana` in
`servicio_programacion_alarmas.dart`), so the two were never merged.
- [x] 10.5 GREEN — restyle the volume/fade-in sliders (cosmetic only, no behaviour change): swapped the raw
`Theme.of(context).textTheme` lookups on `_SectionLabel` ("Sonido y volumen") and the fade-in `ListTile`
title for `context.pluriType.cardTitle` — same weight class, now sharing the named type-scale token with
every other card/section title in the redesign. `Slider` widget types and their `min`/`max`/`value` wiring
are byte-identical, so `'el slider de volumen permite bajar hasta 0.0 (S2-R11)'` passes unmodified.
- [x] 10.6 REFACTOR — confirmed the dismiss-guard test is untouched by this WU (editor sheet only, not the ringing
screen): `git diff` empty for both `pantalla_alarma_sonando.dart` and
`pantalla_alarma_sonando_dismiss_guard_test.dart`; also removed the now-dead `_elegirHora()` method (its only
caller, the old time-picker `_PickerButton`, no longer exists).
- [x] 10.7 Verify — standalone widget test green (7/7); date/fallback/sound round-trip tests green (4/4 new in
`pantalla_alarmas_fecha_test.dart`); full WU10-scoped run (`editor_hora_inline_test.dart` +
`pantalla_alarmas_fecha_test.dart` + `pantalla_alarmas_editor_test.dart` + the two `estado_alarmas*` guard
files + all 3 `pantalla_alarma_sonando*` files + `pantalla_vacaciones_test.dart`): 82/82 green. `flutter
analyze`: 1 issue, identical to baseline.
**`size:exception` recommended.** ~500-650 lines — the largest genuinely-new widget in the plan; already isolated
as its own unit per the proposal ("never bundled"). See forecast table footnote ‡.
**`size:exception` recorded.** Realized: **993 changed lines** (891+/102-) across 21 files — over the 500-650
forecast, same "a strict-TDD commit carries its test files, and any ARB touch drags 13 generated files with it"
pattern as every prior WU (Engram `reference/estimating-strict-tdd-diffs`, id 2514). Breakdown: `lib/` production
code alone is 429 lines (`pantalla_alarmas.dart` 123+/102-, new `editor_hora_inline.dart` 204+/0-) — within the
forecast band on its own; the 3 new/modified test files add 376 lines and the 4 new ARB keys drag in 13 regenerated
`lib/l10n/gen/*.dart` files plus the 2 ARB sources for 188 more. Justification unchanged from the forecast table's
own footnote ‡: "the proposal already isolates WU10 as its own PR, never bundled — splitting further would leave an
unintegrated commit (a widget with no consumer, or a sheet rewrite with no new editor)."
## WU11 — Alarm ringing restyle