docs(openspec): archive android-auto-local-music-paging
Merges its delta requirements into the android-auto-media base spec. This closes out Phase-1 polish for local music; Phase 2 (metadata, sort/filter, real art) and Phase 3 (subfolder scoping, shuffle) remain the only planned future work for this feature.
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
# Proposal: Android Auto Local Music — On-Demand Paging + Friendly Folder Name
|
||||
|
||||
Fast-follow polish to the archived `android-auto-local-music` Phase 1
|
||||
(`archive/2026-07-19-android-auto-local-music/`). NOT Phase 2/3.
|
||||
|
||||
## Intent
|
||||
|
||||
Phase 1 capped each local-music folder at `_maxItemsCarpetaLocal = 50` and
|
||||
silently truncated the rest alphabetically — items past 50 are unreachable.
|
||||
The user rejects silent data loss and wants on-demand incremental loading,
|
||||
with an explicit memory goal: do NOT eagerly build full `MediaItem`s (art,
|
||||
title) for items beyond the page actually shown. Also fold in an archived
|
||||
verify SUGGESTION: settings shows the raw SAF content URI instead of a
|
||||
human-friendly folder name.
|
||||
|
||||
## Scope
|
||||
|
||||
### In Scope
|
||||
- Replace silent truncation in `itemsLocales` with 50-per-page on-demand
|
||||
paging for local-music folders, via a synthetic browsable non-playable
|
||||
"Más…" trailing item (established `MediaBrowserService` workaround — the
|
||||
car UI has no native "load more" signal).
|
||||
- Memory efficiency: hold only the cheap full `NodoLocal` list per browsed
|
||||
level; construct `MediaItem`s (art/title) ONLY for the requested page.
|
||||
Verified by unit test.
|
||||
- Friendly folder-name display in settings `_SeccionMusicaLocal` instead of
|
||||
the raw `content://…/tree/…` URI.
|
||||
- Update ALL 13 `app_*.arb` locale files for any new string (the "Más…"
|
||||
label) — Phase 1's verify caught an en/es-only omission; do not repeat.
|
||||
|
||||
### Out of Scope
|
||||
- Phase 2 (metadata/sort/filter/embedded art) and Phase 3 (subfolder
|
||||
scoping/shuffle) — remain deferred.
|
||||
- Radio-station folders (`_maxItemsPorCarpeta = 50`) keep cap-and-truncate;
|
||||
paging is NOT generalized to radio (user raised local music only; no
|
||||
architectural need forces sharing now).
|
||||
- Native Kotlin paging: `listAudioChildren` already returns the full level;
|
||||
no native offset/limit added.
|
||||
|
||||
## Capabilities
|
||||
|
||||
### New Capabilities
|
||||
None.
|
||||
|
||||
### Modified Capabilities
|
||||
- `android-auto-media`: local-music folder browse replaces silent 50-item
|
||||
truncation with on-demand "Más…" paging. (sdd-spec: confirm exact
|
||||
requirement location; the settings friendly-name fix is phone-UI and may
|
||||
need only a light or no spec delta.)
|
||||
|
||||
## Approach
|
||||
|
||||
Pure-Dart, additive on existing seams. `itemsLocales(nodos, pagina)` sorts
|
||||
the full (cheap) `NodoLocal` list deterministically, then
|
||||
`.skip(pagina*50).take(50).map(_itemLocal)` — so only the page's items are
|
||||
built — and appends a "Más…" item when more remain. The "Más…" media-id
|
||||
encodes `(documentId, siguientePagina)` (new prefix, e.g.
|
||||
`carpeta_local_pag:`); tapping it re-invokes `getChildren`, which
|
||||
re-enumerates that one folder (native already returns the whole level) and
|
||||
returns the next slice. Nothing is cached between taps → minimal memory;
|
||||
deterministic sort keeps page boundaries stable across re-queries. Friendly
|
||||
name via pure-Dart `nombreCarpetaDesdeUri(treeUri)` (decode the tree
|
||||
documentId's trailing path segment; fall back to the raw URI when empty) —
|
||||
zero native surface, fully unit-testable.
|
||||
|
||||
## Affected Areas
|
||||
|
||||
| Area | Impact | Description |
|
||||
|------|--------|-------------|
|
||||
| `lib/servicios/navegacion_auto.dart` | Modified | `itemsLocales` gains page param + "Más…" item; paged media-id predicate/parse; `hijosMusicaLocal` routes paged ids |
|
||||
| `lib/servicios/servicio_audio.dart` | Modified | `getChildren` branch for the paged "Más…" media-id |
|
||||
| `lib/servicios/musica_local_auto.dart` | Modified | Add `nombreCarpetaDesdeUri` helper (pure Dart) |
|
||||
| `lib/pantallas/pantalla_ajustes.dart` | Modified | `_SeccionMusicaLocal` renders friendly name (line ~361) |
|
||||
| `lib/l10n/app_{ar,bn,de,en,es,fr,hi,id,it,ja,pt,ru,zh}.arb` | Modified | New "Más…" label across all 13 locales |
|
||||
| `MainActivity.kt` / `pubspec.yaml` | Unchanged | No native/dep change |
|
||||
|
||||
## Risks
|
||||
|
||||
| Risk | Likelihood | Mitigation |
|
||||
|------|------------|------------|
|
||||
| Re-enumerating the folder on each "Más…" tap repeats one SAF query | Med | Acceptable per-tap cost; deterministic sort keeps pages stable; no cache = minimal memory |
|
||||
| Pure-Dart friendly-name derivation brittle for exotic SAF providers | Med | Fallback to raw URI; native `DocumentFile.getName` left as a design fallback |
|
||||
| Very deep folders still hold full `NodoLocal` list per level | Low | DTOs are tiny; only paged `MediaItem` build is bounded |
|
||||
| l10n omission regresses (missing locales) | Med | Scope all 13 arb files into tasks from the start |
|
||||
|
||||
## Rollback Plan
|
||||
|
||||
Behavioral/additive. Revert = restore `.take(_maxItemsCarpetaLocal)`
|
||||
truncation, drop the paged media-id + "Más…" item, revert the settings
|
||||
subtitle to the raw URI, remove the new arb key. Stations untouched.
|
||||
|
||||
## Dependencies
|
||||
|
||||
None (no new packages, no native changes).
|
||||
|
||||
## Success Criteria
|
||||
|
||||
- [ ] A folder with >50 items exposes every item via "Más…" paging; none
|
||||
silently dropped.
|
||||
- [ ] Only the requested page's `MediaItem`s are constructed — proven by a
|
||||
unit test (page N+1 items not built until page N+1 is requested).
|
||||
- [ ] Settings shows a human-friendly folder name, not the raw content URI.
|
||||
- [ ] All 13 `app_*.arb` files carry the new label.
|
||||
- [ ] No station browse/play regression; pure-Dart fully unit-tested; native
|
||||
unchanged.
|
||||
Reference in New Issue
Block a user