mirror of
https://github.com/immich-app/immich.git
synced 2025-01-24 04:32:45 +01:00
49c4d7cff9
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
131 lines
3.3 KiB
Dart
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;
|
|
}
|
|
}
|