1
0
Fork 0
mirror of https://github.com/immich-app/immich.git synced 2025-01-24 04:32:45 +01:00
immich/mobile/lib/providers/asset_viewer/video_player_value_provider.dart
mertalev 49c4d7cff9
refinements and fixes
fix orientation for remote assets

wip separate widget

separate video loader widget

fixed memory leak

optimized seeking, cleanup

debug context pop

use global key

back to one widget

fixed rebuild

wait for swipe animation to finish

smooth hero animation for remote videos

faster scroll animation
2024-11-16 20:19:08 -05:00

131 lines
3.3 KiB
Dart

import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:native_video_player/native_video_player.dart';
import 'package:video_player/video_player.dart';
enum VideoPlaybackState {
initializing,
paused,
playing,
buffering,
completed,
}
class VideoPlaybackValue {
/// The current position of the video
final Duration position;
/// The total duration of the video
final Duration duration;
/// The current state of the video playback
final VideoPlaybackState state;
/// The volume of the video
final double volume;
const VideoPlaybackValue({
required this.position,
required this.duration,
required this.state,
required this.volume,
});
factory VideoPlaybackValue.fromNativeController(
NativeVideoPlayerController controller,
) {
final playbackInfo = controller.playbackInfo;
final videoInfo = controller.videoInfo;
if (playbackInfo == null || videoInfo == null) {
return videoPlaybackValueDefault;
}
final VideoPlaybackState status = switch (playbackInfo.status) {
PlaybackStatus.playing => VideoPlaybackState.playing,
PlaybackStatus.paused => VideoPlaybackState.paused,
PlaybackStatus.stopped => VideoPlaybackState.completed,
};
return VideoPlaybackValue(
position: Duration(seconds: playbackInfo.position),
duration: Duration(seconds: videoInfo.duration),
state: status,
volume: playbackInfo.volume,
);
}
factory VideoPlaybackValue.fromController(VideoPlayerController? controller) {
final video = controller?.value;
late VideoPlaybackState s;
if (video == null) {
s = VideoPlaybackState.initializing;
} else if (video.isCompleted) {
s = VideoPlaybackState.completed;
} else if (video.isPlaying) {
s = VideoPlaybackState.playing;
} else if (video.isBuffering) {
s = VideoPlaybackState.buffering;
} else {
s = VideoPlaybackState.paused;
}
return VideoPlaybackValue(
position: video?.position ?? Duration.zero,
duration: video?.duration ?? Duration.zero,
state: s,
volume: video?.volume ?? 0.0,
);
}
VideoPlaybackValue copyWith({
Duration? position,
Duration? duration,
VideoPlaybackState? state,
double? volume,
}) {
return VideoPlaybackValue(
position: position ?? this.position,
duration: duration ?? this.duration,
state: state ?? this.state,
volume: volume ?? this.volume,
);
}
}
const VideoPlaybackValue videoPlaybackValueDefault = VideoPlaybackValue(
position: Duration.zero,
duration: Duration.zero,
state: VideoPlaybackState.initializing,
volume: 0.0,
);
final videoPlaybackValueProvider =
StateNotifierProvider<VideoPlaybackValueState, VideoPlaybackValue>((ref) {
return VideoPlaybackValueState(ref);
});
class VideoPlaybackValueState extends StateNotifier<VideoPlaybackValue> {
VideoPlaybackValueState(this.ref) : super(videoPlaybackValueDefault);
final Ref ref;
VideoPlaybackValue get value => state;
set value(VideoPlaybackValue value) {
state = value;
}
set position(Duration value) {
if (state.position == value) return;
state = VideoPlaybackValue(
position: value,
duration: state.duration,
state: state.state,
volume: state.volume,
);
}
void reset() {
state = videoPlaybackValueDefault;
}
}