feat(auto): browse and play local music folders in Android Auto [size:exception]
Phase 1: pick a device folder via SAF (persisted grant, no new permission), browse its nested subfolders/tracks as a 5th Android Auto root folder (hidden until configured), and play tracks through the existing pipeline (EQ, art rotation, cold-start-safe source). No metadata/sort/filter/shuffle yet -- filename is the title, generic rotating art is the placeholder; deferred to a follow-up phase. Adds a new pluriwave/file_actions native method (listAudioChildren) and an onActivityResult override in MainActivity for the SAF folder picker -- both static-review-only, no Android build available here.
This commit is contained in:
@@ -11,6 +11,7 @@ import '../l10n/gen/app_localizations.dart';
|
||||
import '../modelos/emisora.dart';
|
||||
import '../modelos/preset_ecualizador.dart';
|
||||
import 'controlador_reconexion.dart';
|
||||
import 'musica_local_auto.dart';
|
||||
import 'navegacion_auto.dart';
|
||||
import 'servicio_audio_session.dart';
|
||||
import 'servicio_ecualizador.dart';
|
||||
@@ -47,6 +48,17 @@ void registrarFuenteNavegacion(FuenteEmisorasAuto fuente) {
|
||||
_fuenteNavegacionGlobal = fuente;
|
||||
}
|
||||
|
||||
/// Local-music browse source — registered from main.dart, mirrors
|
||||
/// [registrarFuenteNavegacion] above (Design "getChildren data source
|
||||
/// registration"). `null` until registered (headless cold bind before
|
||||
/// main.dart's registration line runs) — every consumer below treats a
|
||||
/// `null` fuente as "not configured" rather than throwing.
|
||||
FuenteMusicaLocalAuto? _fuenteMusicaLocalGlobal;
|
||||
|
||||
void registrarFuenteMusicaLocal(FuenteMusicaLocalAuto fuente) {
|
||||
_fuenteMusicaLocalGlobal = fuente;
|
||||
}
|
||||
|
||||
/// Wrapper de alto nivel para el UI.
|
||||
class ServicioAudio {
|
||||
PluriWaveAudioHandler get _handler {
|
||||
@@ -735,12 +747,20 @@ class PluriWaveAudioHandler extends BaseAudioHandler
|
||||
]) async {
|
||||
try {
|
||||
final constructor = ConstructorArbolAuto();
|
||||
final fuenteLocal = _fuenteMusicaLocalGlobal;
|
||||
if (parentMediaId == AudioService.browsableRootId) {
|
||||
return constructor.raiz();
|
||||
final incluirMusicaLocal =
|
||||
fuenteLocal != null && await fuenteLocal.hayCarpetaConfigurada();
|
||||
return constructor.raiz(incluirMusicaLocal: incluirMusicaLocal);
|
||||
}
|
||||
if (parentMediaId == ConstructorArbolAuto.idEcualizador) {
|
||||
return constructor.presetsEq(PresetEcualizador.presets);
|
||||
}
|
||||
final musicaLocal = await hijosMusicaLocal(
|
||||
parentMediaId,
|
||||
fuente: fuenteLocal,
|
||||
);
|
||||
if (musicaLocal != null) return musicaLocal;
|
||||
final fuente = _fuenteNavegacionGlobal;
|
||||
if (fuente == null) return const [];
|
||||
if (parentMediaId == ConstructorArbolAuto.idFavoritos) {
|
||||
@@ -802,6 +822,20 @@ class PluriWaveAudioHandler extends BaseAudioHandler
|
||||
);
|
||||
return;
|
||||
}
|
||||
// Local-track playback (Design "Local Track Playback Reuses Existing
|
||||
// Pipeline", Spec "User selects a local track"): SECOND branch,
|
||||
// unconditional `return`, mirroring the eq_preset branch above — a
|
||||
// `pista:` id never falls through to the station routing below.
|
||||
if (esPistaMediaId(mediaId)) {
|
||||
final fuenteLocal = _fuenteMusicaLocalGlobal;
|
||||
if (fuenteLocal == null) return;
|
||||
await reproducirPistaLocal(
|
||||
mediaId,
|
||||
fuente: fuenteLocal,
|
||||
reproducir: playMediaItem,
|
||||
);
|
||||
return;
|
||||
}
|
||||
final fuente = _fuenteNavegacionGlobal;
|
||||
if (fuente == null) return;
|
||||
await reproducirPorMediaId(
|
||||
|
||||
Reference in New Issue
Block a user