Files
pluriwave/openspec/changes/android-auto-local-music-paging/apply-progress.md
T
FreeTLab 725169cd31 feat(auto): page local-music folders instead of truncating at 50 [size:exception]
Folders over the 50-item cap now show a "Mas..." item that reveals
the next page on tap, instead of silently dropping the rest. Paging
slices the cheap raw list before building any MediaItem, so items
beyond the requested page are never resolved (art, title) -- proven
by a call-count test. Also swaps the raw SAF content:// URI shown in
settings for a parsed, human-readable folder name with a localized
fallback across all 13 locales.

servicio_audio.dart is untouched; this stays entirely within the
local-music tree/dispatch layer.
2026-07-19 22:14:05 +02:00

156 lines
8.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Apply Progress: android-auto-local-music-paging
Status: DONE — all 18 tasks across 8 phases completed in a single apply batch
(first and only batch), delivered as one PR with `size:exception` per the
resolved delivery strategy.
## Tasks Completed: 18 / 18
- Phase 1 (Paging Primitives): 1.1-1.4 — done
- Phase 2 (Paged Media-ID Scheme): 2.1-2.2 — done
- Phase 3 (Paged `itemsLocales` + "Más…" Item): 3.1-3.5 — done
- Phase 4 (Wire Paged ID into `hijosMusicaLocal`): 4.1-4.2 — done
- Phase 5 (Friendly Folder Name): 5.1-5.2 — done
- Phase 6 (Localization): 6.1 — done (13/13 locales)
- Phase 7 (Settings UI Wiring): 7.1 — done (implementation); widget test
written but not executable in this sandbox (see Deviations)
- Phase 8 (Regression / Manual Follow-Up): 8.1 — done (verified via targeted
test re-runs); 8.2 — deviated as originally documented (manual follow-up,
unchanged from tasks.md's own note)
## TDD Discipline
Strict TDD mode was active. RED was confirmed via actual compile failures
(missing symbols / signature mismatches) before each GREEN implementation
step for:
- `paginaDe<T>` / `hayPaginaSiguiente` (Phase 1) — implemented alongside the
first test batch write (single edit pass covered both primitives), tests
then run and passed; no separate RED capture for this pair specifically
since both are trivial one-line pure functions added in the same edit as
their tests were authored.
- `esCarpetaLocalPaginadaMediaId` / `paginaCarpetaLocalDesde` / paged
`itemsLocales` / paged `hijosMusicaLocal` (Phases 2-4) — RED confirmed via
a full `flutter test test/servicios/navegacion_auto_test.dart` run showing
~20 compile errors (`Method not found`, `No named parameter`) before the
GREEN implementation, then a second run confirming 84/84 passing.
- `nombreCarpetaDesdeUri` (Phase 5) — RED confirmed via
`flutter test test/servicios/musica_local_auto_test.dart` showing 5
`Method not found: 'nombreCarpetaDesdeUri'` compile errors before GREEN,
then 10/10 passing after.
- Settings UI wiring (Phase 7) — RED attempted via
`flutter test test/pantallas/pantalla_ajustes_test.dart`, but this
surfaced a PRE-EXISTING environment blocker unrelated to this change (see
Deviations #1). The implementation was completed to spec regardless.
## Files Changed
Production code:
- `lib/servicios/navegacion_auto.dart` (+119/-lines within diff) — added
top-level `paginaDe<T>`, `hayPaginaSiguiente`; added
`_prefijoCarpetaLocalPaginada`, `esCarpetaLocalPaginadaMediaId`,
`paginaCarpetaLocalDesde`, `_tituloMasLocal`, `_itemMasLocal`; extended
`itemsLocales` signature (`documentIdPadre`, `pagina`, `tamano`,
`@visibleForTesting construirItem`) with slice-then-map ordering (ADR-3);
added paged branch to `hijosMusicaLocal`.
- `lib/servicios/musica_local_auto.dart` (+47 lines) — added pure
`nombreCarpetaDesdeUri(String treeUri, {required String nombreGenerico})`.
Signature note: takes the localized fallback text as a plain `String`
parameter rather than a `BuildContext`, so the function stays pure and
unit-testable without a widget tree (mirrors the
`_formatearDuracion(AppLocalizations l10n, ...)` precedent in
`pantalla_reproductor.dart`, minus the generated-class coupling). This is
a refinement of tasks.md's terse "`nombreCarpetaDesdeUri(String) -> String`"
description, the same kind of abbreviation gap task 3.4 already had for
`itemsLocales`'s full signature.
- `lib/pantallas/pantalla_ajustes.dart` (+5/-2 lines) — `_SeccionMusicaLocal`
subtitle now renders
`nombreCarpetaDesdeUri(carpeta, nombreGenerico: l10n.localMusicFolderGenericName)`
instead of the raw persisted URI; the unconfigured branch is unchanged
(`l10n.localMusicFolderNotConfigured`).
- `lib/l10n/app_{ar,bn,de,en,es,fr,hi,id,it,ja,pt,ru,zh}.arb` (13 files,
+1 key each) — added `localMusicFolderGenericName`, matching each locale's
existing `localMusicFolder*`/`localMusicChoosePath` register. No "Más…"
arb key added anywhere (ADR-5 — that label is hardcoded Spanish car-tree
text, matching every other car-tree label in `navegacion_auto.dart`).
Tests:
- `test/servicios/navegacion_auto_test.dart` (+453 lines) — new groups:
`paginaDe`, `hayPaginaSiguiente`,
`esCarpetaLocalPaginadaMediaId / paginaCarpetaLocalDesde`; rewrote/extended
`ConstructorArbolAuto.itemsLocales` group (call-count invariant, exact-50
boundary, 51-100 two-step, 100+ chained 3+ pages, "Más…" item shape/round
-trip, root paging, stale-page-beyond-range, plus all 8 pre-existing call
sites updated to pass `documentIdPadre`); extended `hijosMusicaLocal`
group with 4 new paged-branch tests.
- `test/servicios/musica_local_auto_test.dart` (+84 lines) — new
`nombreCarpetaDesdeUri` group: internal storage, SD card, nested folder,
storage-root empty-tail fallback, unparseable-URI fallback, never-raw
-URI/never-empty invariant.
- `test/pantallas/pantalla_ajustes_test.dart` (+57 lines) — new group
`_SeccionMusicaLocal — friendly folder name (Phase 7)`: configured folder
shows the derived friendly name (never the raw `content://` URI);
unconfigured folder keeps the existing "not configured" message. Written
to spec but NOT executable in this sandbox (see Deviations #1).
## Test Results (independently re-confirmed)
- `flutter test test/servicios/navegacion_auto_test.dart test/servicios/musica_local_auto_test.dart --concurrency=1 --timeout=60s`
**94 / 94 passing** (84 tests in `navegacion_auto_test.dart` + 10 tests
in `musica_local_auto_test.dart`) — corrected during verify, the figure
above (95/95, 85+10) originally reported here was a counting error.
- `test/pantallas/pantalla_ajustes_test.dart` — NOT run to completion; fails
to COMPILE in this sandbox for reasons that predate this change entirely
(see Deviations #1). The 2 new tests in this file are structurally
complete and should pass once `flutter gen-l10n` is run as part of the
normal manual follow-up (task 8.2), which already covers regenerating
l10n artifacts.
## Diff Size
`git diff --stat`: 19 files changed, 764 insertions(+), 40 deletions(-)
(≈804 changed lines). This exceeds the tasks.md forecast of ~480-600 lines,
mainly because task 3.5's "mechanical" call-site update also required
rewriting one pre-existing assertion (the 60-item cap test) into two new
boundary tests reflecting the spec's cap→paging behavior change, plus the
call-count-invariant test's verbosity (4 assertions × explicit spy
wiring). Delivered as a single PR with `size:exception`, as directed.
## Deviations
1. **`pantalla_ajustes_test.dart` cannot compile in this sandbox —
pre-existing, not introduced by this change.** The tracked
`lib/l10n/gen/app_localizations.dart` is stale: it predates even the
PARENT local-music change and is missing `localMusicFolderNotConfigured`,
`localMusicSectionTitle`, `localMusicFolderTitle`, etc. — getters the
file already referenced BEFORE this apply pass touched anything.
Confirmed by running the targeted test file and observing the compiler
errors point exclusively at pre-existing lines (320-383) before any new
code from this change is even reached. Regenerating the l10n artifacts
requires `flutter gen-l10n`, which is documented to hang in this
environment and was explicitly out of scope for this apply run (per
task 8.2, already flagged as a manual follow-up in the original
tasks.md). The new `localMusicFolderGenericName` getter this change adds
will appear automatically once that regeneration happens — no code
change is needed on top of what's here.
2. **The pre-existing 60-item `itemsLocales` cap test was rewritten, not
just signature-patched**, as part of task 3.5. This was flagged in
tasks.md as "mechanical, no behavior change" for the 8 call sites in
aggregate, but this ONE specific test's assertion (exactly 50 items,
full stop) is incompatible with the spec's Modified Requirement ("Local
Music Folder Item Cap and Paging" — cap-and-truncate replaced by
cap-and-page). It was split into two new tests that assert the correct
NEW behavior (exactly 50 items → no "Más…"; 51-100 items → 50 + "Más…"
then the remainder). This is an intentional, spec-mandated behavior
change, not a regression.
## Risks Carried Forward
- Re-enumerating the folder per "Más…" tap repeats one SAF query per ADR-2
(accepted, documented, out of scope to change here).
- Pure-Dart friendly-name derivation is brittle for exotic SAF providers
(accepted per ADR-4 — degrades to the generic label, never a crash/blank
/raw-URI).
- `flutter analyze` / `flutter gen-l10n` / full `flutter test` were not run
in this session (environment constraint) — task 8.2's original deviation
note stands, now also explains Deviation #1 above.