# Plugin `plugins/google_cast` – Guida pratica / Debug operativo Questa guida è la versione **pratica** del documento di architettura del plugin `google_cast`. L’obiettivo è aiutarti a capire **rapidamente**: - quale parte del flusso è coinvolta - quale file toccare - dove guardare quando qualcosa non funziona - come distinguere i problemi **Google Cast standard** dai problemi **Custom Receiver** --- # 1. Mappa mentale rapida ## Flusso generale ```text Flutter UI ↓ cast_controller.dart ↓ ┌───────────────────────────────┬───────────────────────────────┐ │ GoogleCastController │ CustomCastController │ │ (Google Cast standard) │ (Custom Receiver CAF/web) │ └───────────────┬───────────────┴───────────────┬───────────────┘ ↓ ↓ MethodChannel('google_cast') MethodChannel('google_cast') ↓ ↓ FlutterCastFrameworkPlugin.kt (Android) ↓ ┌──────────────┬───────────────┬──────────────┬──────────────┐ │ Context │ Session │ MediaClient │ QueueManager │ │ Manager │ Handler │ │ │ └──────────────┴───────────────┴──────────────┴──────────────┘ ↓ Google Cast framework / Receiver ``` --- # 2. File principali: a cosa servono in pratica ## Lato Flutter / App ### `lib/widgets/cast/cast_controller.dart` **È la facciata unificata**. Usalo per capire: - quale backend è attivo (`google`, `custom`, `dlna`) - dove finiscono i comandi UI - come vengono sincronizzati i notifier condivisi: - indice corrente - stato play/pause - posizione/durata - volume/mute ### Se hai un bug tipo: - il pulsante UI chiama il backend sbagliato - i notifier non si aggiornano - la cast bar chiama il backend sbagliato 👉 il primo file da guardare è **questo**. --- ### `lib/widgets/cast/google_cast_controller.dart` **È il cervello Dart del Google Cast standard**. Qui trovi: - connessione del flusso Google Cast - caricamento queue standard - slideshow lato Flutter - polling media/volume - sync verso fullscreen viewer / controlli ### Se hai un bug tipo: - slideshow Google si ferma - foto/video si comportano male - seek cambia sulla TV ma non sul telefono - volume non si aggiorna nella UI - `onCastReady` genera comportamenti strani 👉 guarda **questo file**. --- ### `lib/widgets/cast/custom_cast_controller.dart` **È il cervello Dart del Custom Receiver**. Qui trovi: - avvio sessione/receiver custom - invio messaggi JSON al receiver web - polling custom (`MEDIA_STATUS`, `VOLUME_STATUS`) - slideshow custom - comandi `LOAD_QUEUE`, `NEXT`, `PLAY`, `PAUSE`, ecc. ### Se hai un bug tipo: - Custom connect funziona ma la TV mostra male il contenuto - overlay/progress duplicati - volume custom non cambia davvero il video - il receiver risponde ma Flutter non si aggiorna 👉 guarda **questo file** + il receiver web. --- ### `lib/widgets/collection/app_bar/cast/cast_icon_button.dart` Gestisce il **tap sull’icona Cast** nella app bar. Qui si decide se il tap deve fare: - solo **connessione device** - oppure connessione + media ### Se hai un bug tipo: - scegli Google ma sembra partire Custom - il cast parte subito quando scegli il device - il device si connette ma la UX è sbagliata 👉 guarda **questo file**. --- ### `lib/widgets/collection/app_bar/cast/cast_bar_inline.dart` È la **seconda barra orizzontale** con: - cast manuale - fullscreen cast - slideshow - prev/next - stop slideshow - stop cast ### Se hai un bug tipo: - parte con gli item sbagliati - usa una selezione vecchia - startIndex invalido - overflow orizzontale della barra 👉 guarda **questo file**. --- ### `lib/widgets/collection/app_bar/cast/cast_controls_sheet.dart` È il **bottom sheet dei controlli**. Qui trovi: - seek - prev/play-pause/next - volume/mute - stop slideshow - stop cast ### Se hai un bug tipo: - il volume non compare - il volume compare ma non si aggiorna - i controlli interagiscono col backend sbagliato - la UI chiama `controller.google` / `controller.custom` direttamente 👉 guarda **questo file**. --- ### `lib/widgets/viewer/fullscreen_cast_viewer.dart` È il viewer fullscreen locale sincronizzato col Cast. ### Se hai un bug tipo: - il video sulla TV cambia seek ma il telefono no - il fullscreen non segue l’indice Cast - il video locale e il Cast non sono allineati 👉 guarda **questo file**. --- ## Lato plugin Android ### `plugins/google_cast/android/src/main/kotlin/com/aves/google_cast/FlutterCastFrameworkPlugin.kt` **Router centrale del plugin**. Riceve tutto dal `MethodChannel('google_cast')`. ### Se hai un bug tipo: - Flutter chiama un metodo ma sembra non arrivare al native - un comando non viene instradato bene - un handler non viene più registrato 👉 guarda **questo file**. --- ### `CastContextManager.kt` Gestisce: - `CastContext` - `Activity` - sessione Cast corrente - `RemoteMediaClient` ### Se hai un bug tipo: - sessione non trovata - device connesso ma client nullo - callback non agganciata al client corretto 👉 guarda **questo file**. --- ### `CastSessionHandler.kt` Gestisce gli eventi di sessione: - `onSessionStarted` - `onSessionResumed` - `onSessionEnded` - `onCastReady` - `onCastStopped` ### Se hai un bug tipo: - il device si connette ma Flutter non sa che è pronto - la seconda barra non compare - la sessione finisce ma Flutter resta “connected” 👉 guarda **questo file**. --- ### `CastDialogLauncher.kt` Mostra il dialog nativo di selezione device. ### Se hai un bug tipo: - l’icona Cast non apre il picker - il picker si apre ma non seleziona device 👉 guarda **questo file**. --- ### `CastMediaClient.kt` Gestisce: - play / pause / seek - get media status - volume / mute - callback `RemoteMediaClient.Callback` ### Se hai un bug tipo: - `onQueueIndexChanged` non arriva più a Flutter - `onVideoFinished` non arriva - `Invalid Request` - volume nativo Google non si aggiorna 👉 guarda **questo file**. --- ### `CastQueueManager.kt` Gestisce: - `loadQueue(items, startIndex)` - `next()` - `prev()` - costruzione `MediaQueueItem` - metadati (`index`, `isVideo`, mime, title) ### Se hai un bug tipo: - `Invalid startIndex` - queue rotta o item sbagliati - Google Cast non va al prossimo item come dovrebbe 👉 guarda **questo file**. --- ### `CastCustomReceiver.kt` Gestisce l’avvio del custom receiver web/CAF. ### Se hai un bug tipo: - il receiver custom non parte - parte ma non riceve messaggi - la sessione custom sembra connettersi ma non carica nulla 👉 guarda **questo file**. --- # 3. Mappa dei comandi principali ## Comandi Flutter → plugin Android ### Connessione - `showCastDialog` - `startCustomReceiver` ### Queue / navigazione - `loadQueue` - `next` - `prev` ### Media - `play` - `pause` - `seekTo` - `getMediaStatus` ### Volume - `getVolume` - `setVolume` - `setMute` ### Stop - `stopCast` --- # 4. Mappa degli eventi di ritorno ## Google Cast standard → Flutter - `onCastReady` - `onCastStopped` - `onQueueIndexChanged` - `onVideoFinished` - `onCastError` ## Custom Receiver → Flutter Di solito via messaggi custom, per esempio: - `CAST_READY` - `CAST_STOPPED` - `MEDIA_STATUS` - `VOLUME_STATUS` --- # 5. Troubleshooting rapido ## Problema: seleziono il device e subito compaiono - `Invalid Request` - `MediaQueue error 2001` - `IDLE_REASON_ERROR` ### Causa probabile Il polling media parte **troppo presto**, cioè già su `onCastReady` quando non esiste ancora una queue/media caricata. ### Dove guardare - `google_cast_controller.dart` - `CastMediaClient.kt` ### Fix tipico - non avviare `startMediaPolling()` dentro `onCastReady` - far partire il polling solo dopo `loadQueue` - lato native, ignorare gli stati in cui `mediaInfo == null` --- ## Problema: slideshow Google fa prima e seconda foto, poi si ferma ### Causa probabile Flutter non riceve più il cambio item queue, quindi il timer slideshow non viene riarmato. ### Dove guardare - `google_cast_controller.dart` - `CastMediaClient.kt` - eventualmente `CastQueueManager.kt` ### Fix tipico - ripristinare la callback `RemoteMediaClient.Callback` - reinviare a Flutter `onQueueIndexChanged(index, isVideo)` - in Dart riarmare il timer solo per le foto --- ## Problema: in slideshow un video viene saltato dopo 5 secondi ### Causa probabile Il timer slideshow delle foto parte anche sui video. ### Dove guardare - `google_cast_controller.dart` - `custom_cast_controller.dart` ### Comportamento corretto - **foto** → timer - **video** → nessun timer, deve finire da solo e poi passare al successivo --- ## Problema: in presentazione manuale/fullscreen le foto avanzano da sole ### Causa probabile La logica slideshow è rimasta attiva quando non dovrebbe. ### Dove guardare - `google_cast_controller.dart` - `custom_cast_controller.dart` - `cast_bar_inline.dart` ### Comportamento corretto - **manuale/fullscreen**: le foto restano ferme fino a un comando manuale - i video invece vanno al successivo a fine riproduzione --- ## Problema: `Invalid startIndex: X` ### Causa probabile Stai caricando una queue con un indice iniziale più grande della lunghezza della lista. ### Dove guardare - `cast_bar_inline.dart` - `google_cast_controller.dart` - `custom_cast_controller.dart` - `CastQueueManager.kt` ### Fix tipico - usare `startIndex: 0` nei comandi manuali della cast bar - oppure proteggere con una funzione tipo `_safeIndexOrKeep(...)` --- ## Problema: seek sul video cambia sulla TV ma non sul telefono ### Causa probabile Il telefono usa un player locale non sincronizzato con `positionNotifier` / `isPlayingNotifier` del Cast. ### Dove guardare - `google_cast_controller.dart` - `fullscreen_cast_viewer.dart` ### Fix tipico - in `seekCast()` aggiornare subito `positionNotifier` - nel `VideoWidget` locale ascoltare `positionNotifier` e `isPlayingNotifier` --- ## Problema: il volume compare ma la barra non si aggiorna ### Causa probabile Il comando volume parte, ma il notifier locale non viene riallineato con lo stato reale del device. ### Dove guardare - `google_cast_controller.dart` - `cast_controls_sheet.dart` - `fullscreen_cast_viewer.dart` - `CastMediaClient.kt` ### Fix tipico - dopo `setVolume` e `setMute`, chiamare `refreshVolumeStatus()` - lato UI, separare `onChanged` e `onChangeEnd` dello slider --- ## Problema: scegli Google ma sembra partire Custom ### Causa probabile Il backend attivo del controller unificato non è allineato al backend scelto nella UI. ### Dove guardare - `cast_icon_button.dart` - `cast_controller.dart` - `custom_cast_controller.dart` - `google_cast_controller.dart` ### Fix tipico - rendere l’icona Cast “connect-only” - impostare esplicitamente il backend attivo (`_backend`) nel controller unificato - far partire la queue solo dai pulsanti della cast bar --- ## Problema: in selection mode la app bar sembra toccare anche le foto sotto ### Causa probabile La barra non sta assorbendo correttamente i tocchi nell’area header. ### Dove guardare - `collection_app_bar.dart` - `aves_app_bar.dart` - `collection_page.dart` ### Fix tipico - ripristinare il wrapper che assorbe i tap nella barra (`AInkResponse`) - verificare il comportamento `pinned` - verificare l’uso corretto di `appBarHeightNotifier` --- # 6. Regole pratiche di debug ## Regola 1 ### Se il problema è “UI Flutter non aggiornata” Guarda prima i controller Dart: - `cast_controller.dart` - `google_cast_controller.dart` - `custom_cast_controller.dart` - `fullscreen_cast_viewer.dart` --- ## Regola 2 ### Se il problema è “la TV/device fa una cosa diversa da Flutter” Guarda: - `CastMediaClient.kt` - `CastQueueManager.kt` - receiver custom JS/HTML (se custom) --- ## Regola 3 ### Se il problema avviene subito dopo la connessione device Guarda: - `CastSessionHandler.kt` - `google_cast_controller.dart` - `CastMediaClient.kt` Il sospetto classico è la distinzione: - connessione sessione - queue realmente caricata --- ## Regola 4 ### Se il problema riguarda slideshow foto/video Guarda prima il controller Dart, poi il native. Ordine consigliato: 1. `google_cast_controller.dart` 2. `custom_cast_controller.dart` 3. `CastMediaClient.kt` 4. `CastQueueManager.kt` --- ## Regola 5 ### Se il problema riguarda il Custom Receiver Non fermarti al controller Flutter. Devi guardare anche: - `CastCustomReceiver.kt` - `receiver.html` - eventuale JS del receiver Perché molti bug Custom sono **receiver-side**, non plugin-side. --- # 7. Differenza pratica Google vs Custom (da tenere a mente) ## Google Cast standard ### Più affidabile quando: - usi queue nativa - usi volume Cast nativo - ti affidi a `RemoteMediaClient.Callback` ## Custom Receiver ### Più flessibile quando: - vuoi UI custom sul TV - vuoi logica media personalizzata - vuoi controllare il player HTML5 direttamente ### Ma più fragile quando: - volume/mute non sono implementati davvero - il DOM del receiver non viene pulito bene - i messaggi receiver/Flutter non sono perfettamente allineati --- # 8. Checklist rapida: dove toccare per ogni categoria ## Connessione device - `cast_icon_button.dart` - `FlutterCastFrameworkPlugin.kt` - `CastDialogLauncher.kt` - `CastSessionHandler.kt` ## Queue / media non partono - `cast_bar_inline.dart` - `google_cast_controller.dart` - `CastQueueManager.kt` ## Slideshow foto/video - `google_cast_controller.dart` - `custom_cast_controller.dart` - `CastMediaClient.kt` ## Volume Google - `google_cast_controller.dart` - `cast_controls_sheet.dart` - `fullscreen_cast_viewer.dart` - `CastMediaClient.kt` ## Volume Custom - `custom_cast_controller.dart` - `CastCustomReceiver.kt` - `receiver.html` / JS ## Bug UI selection / app bar - `collection_app_bar.dart` - `aves_app_bar.dart` - `collection_page.dart` --- # 9. Conclusione pratica Se devi pensare al plugin in modo operativo, ricordati questa formula: ## **Flutter decide l’UX → il plugin Android parla con Cast → il receiver riproduce davvero** Quindi ogni bug va classificato subito in una di queste tre famiglie: ### A. Bug UX / Flutter - notifier - selection - fullscreen viewer - cast bar - app bar ### B. Bug plugin Android - sessione - queue - callback media - volume nativo ### C. Bug receiver - volume custom - progress bar duplicate - media status custom - UI TV-side Capire **subito** in quale famiglia rientra il bug fa risparmiare tantissimo tempo di debug.