# 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.
