immich/mobile/lib/providers/cast.provider.dart
Brandon Wees 5574b2dd39
feat(mobile): add cast support (#18341)
* initial cast framework complete and mocked cast dialog working

* wip casting

* casting works!

just need to add session key check and remote video controls

* cleanup of classes

* add session expiration checks

* cast dialog now shows connected device at top of list with a list header. Discovered devices are also cached for app session.

* cast video player finalized

* show fullsize assets on casting

* translation already happens on the text element

* remove prints

* fix lintings

* code review changes from @shenlong-tanwen

* fix connect method override

* fix alphabetization

* remove important

* filter chromecast audio devices

* fix some disconnect command ordering issues and unawaited futures

* remove prints

* only disconnect if we are connected

* don't try to reconnect if its the current device

* add cast button to top bar

* format sessions api

* more formatting issues fixed

* add snack bar to tell user that we cannot cast an asset that is not uploaded to server

* make casting icon change to primary color when casting is active

* only show casting snackbar if we are casting

* dont show cast button if asset is remote and we are not casting

* stop playing media if we seek to an asset that is not remote

* remove https check since it works with local http IP addresses

* remove unneeded imports

* fix recasting when socket closes

* fix info plist formatting

* only show cast button if there is an active websocket connection (ie the server is accessible)

* add device capability bitmask checks

* small comment about bitmask
2025-06-08 21:55:23 -05:00

94 lines
2.5 KiB
Dart

import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/entities/asset.entity.dart';
import 'package:immich_mobile/interfaces/cast_destination_service.interface.dart';
import 'package:immich_mobile/models/cast/cast_manager_state.dart';
import 'package:immich_mobile/services/gcast.service.dart';
final castProvider = StateNotifierProvider<CastNotifier, CastManagerState>(
(ref) => CastNotifier(ref.watch(gCastServiceProvider)),
);
class CastNotifier extends StateNotifier<CastManagerState> {
// more cast providers can be added here (ie Fcast)
final ICastDestinationService _gCastService;
List<(String, CastDestinationType, dynamic)> discovered = List.empty();
CastNotifier(this._gCastService)
: super(
const CastManagerState(
isCasting: false,
currentTime: Duration.zero,
duration: Duration.zero,
receiverName: '',
castState: CastState.idle,
),
) {
_gCastService.onConnectionState = _onConnectionState;
_gCastService.onCurrentTime = _onCurrentTime;
_gCastService.onDuration = _onDuration;
_gCastService.onReceiverName = _onReceiverName;
_gCastService.onCastState = _onCastState;
}
void _onConnectionState(bool isCasting) {
state = state.copyWith(isCasting: isCasting);
}
void _onCurrentTime(Duration currentTime) {
state = state.copyWith(currentTime: currentTime);
}
void _onDuration(Duration duration) {
state = state.copyWith(duration: duration);
}
void _onReceiverName(String receiverName) {
state = state.copyWith(receiverName: receiverName);
}
void _onCastState(CastState castState) {
state = state.copyWith(castState: castState);
}
void loadMedia(Asset asset, bool reload) {
_gCastService.loadMedia(asset, reload);
}
Future<void> connect(CastDestinationType type, dynamic device) async {
switch (type) {
case CastDestinationType.googleCast:
await _gCastService.connect(device);
break;
}
}
Future<List<(String, CastDestinationType, dynamic)>> getDevices() async {
if (discovered.isEmpty) {
discovered = await _gCastService.getDevices();
}
return discovered;
}
void play() {
_gCastService.play();
}
void pause() {
_gCastService.pause();
}
void seekTo(Duration position) {
_gCastService.seekTo(position);
}
void stop() {
_gCastService.stop();
}
Future<void> disconnect() async {
await _gCastService.disconnect();
}
}