// lib/widgets/cast/cast_controller.dart // NUOVA VERSIONE MODULARE // - Orchestratore leggero // - Nessuna logica Google/DLNA/FAST // - Delega tutto ai backend specializzati import 'package:flutter/material.dart'; import 'package:aves/model/entry/entry.dart'; import 'backends/google_cast_backend.dart'; import 'backends/fast_cast_backend.dart'; import 'backends/dlna_cast_backend.dart'; import 'google_cast_controller.dart'; import 'package:shared_preferences/shared_preferences.dart'; enum CastBackend { google, fast, dlna } enum CastIconState { idle, connecting, connected } class CastController { CastController._(); static final CastController instance = CastController._(); static const _prefBackend = 'cast_backend'; // Stato UI unificato (rimane qui) final castIconState = ValueNotifier(CastIconState.idle); final isCastingNotifier = ValueNotifier(false); final currentIndexNotifier = ValueNotifier(0); final isPlayingNotifier = ValueNotifier(false); final isBufferingNotifier = ValueNotifier(false); final positionNotifier = ValueNotifier(Duration.zero); final durationNotifier = ValueNotifier(Duration.zero); final volumeNotifier = ValueNotifier(1.0); final isMutedNotifier = ValueNotifier(false); // Backend selezionato (persistenza opzionale) final backendNotifier = ValueNotifier(CastBackend.google); // Backend attivo late CastBackendBase backend; // ------------------------------------------------------------ // SELEZIONE BACKEND // ------------------------------------------------------------ Future setBackend(CastBackend type) async { backendNotifier.value = type; // Persistenza final prefs = await SharedPreferences.getInstance(); await prefs.setString(_prefBackend, type.name); // Ricrea backend switch (type) { case CastBackend.google: backend = GoogleCastBackend(this); GoogleCastController.instance.activateMethodChannelHandler(); break; case CastBackend.fast: backend = FastCastBackend(this); // FAST non deve toccare il MethodChannel Google break; case CastBackend.dlna: backend = DlnaCastBackend(this); // DLNA non deve toccare il MethodChannel Google break; } // Reset stato icona castIconState.value = CastIconState.idle; isCastingNotifier.value = false; } Future loadSavedBackend() async { final prefs = await SharedPreferences.getInstance(); final saved = prefs.getString(_prefBackend); CastBackend type; switch (saved) { case 'google': type = CastBackend.google; break; case 'fast': type = CastBackend.fast; break; case 'dlna': type = CastBackend.dlna; break; default: type = CastBackend.google; } await setBackend(type); } // ------------------------------------------------------------ // API UNIFICATA (DELEGA AI BACKEND) // ------------------------------------------------------------ Future startCast(List entries, int index) => backend.startCast(entries, index); Future startFullscreen(List entries, int index) => backend.startFullscreen(entries, index); Future startSlideshow(List entries, int index) => backend.startSlideshow(entries, index); Future startManualQueue(List entries, int index) => backend.startManualQueue(entries, index); Future nextManual() => backend.nextManual(); Future prevManual() => backend.prevManual(); Future stopCast() => backend.stopCast(); // ------------------------------------------------------------ // Accesso diretto al controller Google Cast (per dialog Android) // ------------------------------------------------------------ GoogleCastController get google => GoogleCastController.instance; } // ------------------------------------------------------------ // CLASSE BASE PER TUTTI I BACKEND // ------------------------------------------------------------ abstract class CastBackendBase { final CastController controller; CastBackendBase(this.controller); Future startCast(List entries, int index); Future startFullscreen(List entries, int index); Future startSlideshow(List entries, int index); Future startManualQueue(List entries, int index); Future nextManual(); Future prevManual(); Future stopCast(); // PATCH: ogni backend decide il delay dello slideshow Duration? getNextDelay(AvesEntry entry); }