aves_mio100/lib/widgets/cast/cast_state.dart
2026-07-06 14:52:45 +02:00

145 lines
4.1 KiB
Dart

import 'package:aves/model/entry/entry.dart';
import 'package:aves/widgets/dialogs/cast_dialog.dart';
import 'package:flutter/foundation.dart';
class CastState {
CastState._();
static final CastState instance = CastState._();
// Target selezionato (DLNA o altri target custom)
final ValueNotifier<CastTarget?> targetNotifier = ValueNotifier(null);
// Cast armato (mostra la cast bar)
final ValueNotifier<bool> armedNotifier = ValueNotifier(false);
// Queue selezionata
final ValueNotifier<List<AvesEntry>> pendingQueueNotifier =
ValueNotifier(const []);
// Indice corrente
final ValueNotifier<int> currentIndexNotifier = ValueNotifier(0);
// Da dove è stato armato
final ValueNotifier<String?> sourceRouteNotifier = ValueNotifier(null);
// ---------------------------------------------------------------------------
// GETTER
// ---------------------------------------------------------------------------
/// Nome del device mostrato nella Cast Bar
///
/// NOTA:
/// - Google Cast rimosso (non esiste nella tua build)
/// - DLNA: device noto lato Dart
String? get deviceName {
final t = targetNotifier.value;
// 🔥 GoogleCastTarget rimosso
// if (t is GoogleCastTarget) return 'Google Cast';
if (t is DlnaTarget) {
return t.device.info.friendlyName;
}
return null;
}
bool get isArmed =>
armedNotifier.value && targetNotifier.value != null;
List<AvesEntry> get queue => pendingQueueNotifier.value;
bool get hasPendingQueue => queue.isNotEmpty;
int get currentIndex => currentIndexNotifier.value;
set currentIndex(int value) {
if (queue.isEmpty) {
currentIndexNotifier.value = 0;
} else {
if (value < 0) value = 0;
if (value >= queue.length) value = queue.length - 1;
currentIndexNotifier.value = value;
}
currentIndexNotifier.notifyListeners();
}
bool get hasPrevious =>
queue.isNotEmpty && currentIndex > 0;
bool get hasNext =>
queue.isNotEmpty && currentIndex < queue.length - 1;
AvesEntry? get previousEntry {
if (!hasPrevious) return null;
currentIndexNotifier.value -= 1;
currentIndexNotifier.notifyListeners();
return queue[currentIndexNotifier.value];
}
AvesEntry? get nextEntry {
if (!hasNext) return null;
currentIndexNotifier.value += 1;
currentIndexNotifier.notifyListeners();
return queue[currentIndexNotifier.value];
}
// ---------------------------------------------------------------------------
// SET QUEUE
// ---------------------------------------------------------------------------
void setQueue(List<AvesEntry> entries) {
pendingQueueNotifier.value = entries;
currentIndexNotifier.value = 0;
pendingQueueNotifier.notifyListeners();
currentIndexNotifier.notifyListeners();
}
// ---------------------------------------------------------------------------
// ARM / DISARM
// ---------------------------------------------------------------------------
void arm(
CastTarget target, {
List<AvesEntry> queue = const [],
String? sourceRoute,
}) {
targetNotifier.value = target;
pendingQueueNotifier.value = queue;
currentIndexNotifier.value = 0;
sourceRouteNotifier.value = sourceRoute;
armedNotifier.value = true;
targetNotifier.notifyListeners();
pendingQueueNotifier.notifyListeners();
currentIndexNotifier.notifyListeners();
armedNotifier.notifyListeners();
}
void updateQueue(List<AvesEntry> queue) {
pendingQueueNotifier.value = queue;
if (currentIndex >= queue.length) {
currentIndexNotifier.value = 0;
}
pendingQueueNotifier.notifyListeners();
currentIndexNotifier.notifyListeners();
}
/// Disarma il cast e resetta lo stato UI
///
/// NOTA:
/// - Non azzeriamo `targetNotifier` per evitare glitch di rebuild
void disarm() {
armedNotifier.value = false;
pendingQueueNotifier.value = const [];
currentIndexNotifier.value = 0;
sourceRouteNotifier.value = null;
armedNotifier.notifyListeners();
pendingQueueNotifier.notifyListeners();
currentIndexNotifier.notifyListeners();
}
}