feat(auto): real metadata, quality sort and name buckets for local music [size:exception]
Local tracks now show embedded title/artist/album art (via native MediaMetadataRetriever, cached through the existing FileProvider) instead of the raw filename, falling back gracefully when a file has no usable tags. Adds two navigable entry points per folder: sort by audio quality (bitrate, capped at 150 tracks per folder to bound worst-case latency) and alphabetical name buckets -- the closest realistic form of "filtering" given Android Auto has no text-search UI in this integration. Metadata resolves only for the page actually being browsed (same slice-cheap-then-map discipline as the paging change), backed by a flat 256-entry LRU session cache that survives across pages. No new permission, no new pub dependency, no l10n changes (car-tree labels stay hardcoded Spanish, matching every existing label in the tree).
This commit is contained in:
@@ -23,14 +23,19 @@ class NodoLocal {
|
||||
final bool esDirectorio;
|
||||
}
|
||||
|
||||
/// Minimal playable local track (Design "Phase 1 minimal shape" — no
|
||||
/// artist/album/duration metadata per spec's "Not in this delta"). Pure
|
||||
/// DTO — no behavior, so no unit tests are warranted for it on its own.
|
||||
/// Playable local track (Phase 2 extends the Phase 1 minimal shape with
|
||||
/// resolved embedded metadata — Design "Data Flow"). Pure DTO — no
|
||||
/// behavior, so no unit tests are warranted for it on its own beyond
|
||||
/// construction (`pista_local_test.dart`).
|
||||
class PistaLocal {
|
||||
const PistaLocal({
|
||||
required this.documentId,
|
||||
required this.titulo,
|
||||
required this.contentUri,
|
||||
this.artista,
|
||||
this.embeddedArtUri,
|
||||
this.bitrate,
|
||||
this.sampleRate,
|
||||
});
|
||||
|
||||
/// Opaque SAF document id for this track.
|
||||
@@ -43,4 +48,54 @@ class PistaLocal {
|
||||
/// Playable `content://` URI resolved via
|
||||
/// `FuenteMusicaLocalAuto.uriContenidoDePista`.
|
||||
final String contentUri;
|
||||
|
||||
/// Resolved embedded artist metadata, when available (Design "Interfaces
|
||||
/// / Contracts" — `readAudioMetadataBatch`). `null` when unresolved or
|
||||
/// unavailable.
|
||||
final String? artista;
|
||||
|
||||
/// Resolved embedded-art `content://` URI served via the app's
|
||||
/// `FileProvider` cache (Design ADR-1). `null` when there is no embedded
|
||||
/// picture or it could not be resolved.
|
||||
final String? embeddedArtUri;
|
||||
|
||||
/// Resolved bitrate in bits per second, when available.
|
||||
final int? bitrate;
|
||||
|
||||
/// Resolved sample rate in Hz, only available on API 31+ (Design ADR-5).
|
||||
/// `null` on older API levels or when unresolved.
|
||||
final int? sampleRate;
|
||||
}
|
||||
|
||||
/// Resolved embedded metadata for a single local track (Design "Interfaces
|
||||
/// / Contracts"): one entry per requested `documentId`, all fields
|
||||
/// individually nullable (per-field parse failures degrade gracefully
|
||||
/// instead of dropping the whole entry). Pure DTO — no behavior, so no
|
||||
/// unit tests are warranted for it on its own beyond construction
|
||||
/// (`pista_local_test.dart`).
|
||||
class MetadatosPista {
|
||||
const MetadatosPista({
|
||||
this.titulo,
|
||||
this.artista,
|
||||
this.artUri,
|
||||
this.bitrate,
|
||||
this.sampleRate,
|
||||
});
|
||||
|
||||
/// Resolved embedded title, or `null` when absent/unparseable.
|
||||
final String? titulo;
|
||||
|
||||
/// Resolved embedded artist, or `null` when absent/unparseable.
|
||||
final String? artista;
|
||||
|
||||
/// Resolved embedded-art `content://` URI (Design ADR-1), or `null` when
|
||||
/// there is no embedded picture or it could not be resolved/served.
|
||||
final String? artUri;
|
||||
|
||||
/// Resolved bitrate in bits per second, or `null` when unknown.
|
||||
final int? bitrate;
|
||||
|
||||
/// Resolved sample rate in Hz (API 31+ only, Design ADR-5), or `null`
|
||||
/// when unknown/unsupported on this API level.
|
||||
final int? sampleRate;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user