mirror of
https://github.com/immich-app/immich.git
synced 2025-07-09 03:06:56 -04:00
fix: handle buffering
This commit is contained in:
parent
bfd89d162e
commit
abe9b50f58
@ -1,3 +1,5 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_hooks/flutter_hooks.dart' hide Store;
|
import 'package:flutter_hooks/flutter_hooks.dart' hide Store;
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
@ -33,6 +35,28 @@ class NativeVideoViewerPage extends HookConsumerWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final controller = useState<NativeVideoPlayerController?>(null);
|
final controller = useState<NativeVideoPlayerController?>(null);
|
||||||
|
final lastVideoPosition = useRef(-1);
|
||||||
|
final isBuffering = useRef(false);
|
||||||
|
|
||||||
|
void checkIfBuffering([Timer? timer]) {
|
||||||
|
if (!context.mounted) {
|
||||||
|
timer?.cancel();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final videoPlayback = ref.read(videoPlaybackValueProvider);
|
||||||
|
if ((isBuffering.value ||
|
||||||
|
videoPlayback.state == VideoPlaybackState.initializing) &&
|
||||||
|
videoPlayback.state != VideoPlaybackState.buffering) {
|
||||||
|
ref.read(videoPlaybackValueProvider.notifier).value =
|
||||||
|
videoPlayback.copyWith(state: VideoPlaybackState.buffering);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// timer to mark videos as buffering if the position does not change
|
||||||
|
final bufferingTimer = useRef<Timer>(
|
||||||
|
Timer.periodic(const Duration(seconds: 5), checkIfBuffering),
|
||||||
|
);
|
||||||
|
|
||||||
Future<VideoSource> createSource(Asset asset) async {
|
Future<VideoSource> createSource(Asset asset) async {
|
||||||
if (asset.isLocal && asset.livePhotoVideoId == null) {
|
if (asset.isLocal && asset.livePhotoVideoId == null) {
|
||||||
@ -100,6 +124,15 @@ class NativeVideoViewerPage extends HookConsumerWidget {
|
|||||||
final videoPlayback =
|
final videoPlayback =
|
||||||
VideoPlaybackValue.fromNativeController(controller.value!);
|
VideoPlaybackValue.fromNativeController(controller.value!);
|
||||||
ref.read(videoPlaybackValueProvider.notifier).value = videoPlayback;
|
ref.read(videoPlaybackValueProvider.notifier).value = videoPlayback;
|
||||||
|
// Check if the video is buffering
|
||||||
|
if (videoPlayback.state == VideoPlaybackState.playing) {
|
||||||
|
isBuffering.value =
|
||||||
|
lastVideoPosition.value == videoPlayback.position.inSeconds;
|
||||||
|
lastVideoPosition.value = videoPlayback.position.inSeconds;
|
||||||
|
} else {
|
||||||
|
isBuffering.value = false;
|
||||||
|
lastVideoPosition.value = -1;
|
||||||
|
}
|
||||||
final state = videoPlayback.state;
|
final state = videoPlayback.state;
|
||||||
|
|
||||||
// Enable the WakeLock while the video is playing
|
// Enable the WakeLock while the video is playing
|
||||||
@ -142,6 +175,8 @@ class NativeVideoViewerPage extends HookConsumerWidget {
|
|||||||
|
|
||||||
final videoSource = await createSource(asset);
|
final videoSource = await createSource(asset);
|
||||||
controller.value?.loadVideoSource(videoSource);
|
controller.value?.loadVideoSource(videoSource);
|
||||||
|
|
||||||
|
Timer(const Duration(milliseconds: 200), checkIfBuffering);
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(
|
useEffect(
|
||||||
@ -158,6 +193,7 @@ class NativeVideoViewerPage extends HookConsumerWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return () {
|
return () {
|
||||||
|
bufferingTimer.value.cancel();
|
||||||
controller.value?.onPlaybackPositionChanged
|
controller.value?.onPlaybackPositionChanged
|
||||||
.removeListener(onPlaybackPositionChanged);
|
.removeListener(onPlaybackPositionChanged);
|
||||||
controller.value?.onPlaybackStatusChanged
|
controller.value?.onPlaybackStatusChanged
|
||||||
@ -169,9 +205,6 @@ class NativeVideoViewerPage extends HookConsumerWidget {
|
|||||||
[],
|
[],
|
||||||
);
|
);
|
||||||
|
|
||||||
void updatePlayback(VideoPlaybackValue value) =>
|
|
||||||
ref.read(videoPlaybackValueProvider.notifier).value = value;
|
|
||||||
|
|
||||||
final size = MediaQuery.sizeOf(context);
|
final size = MediaQuery.sizeOf(context);
|
||||||
|
|
||||||
return SizedBox(
|
return SizedBox(
|
||||||
@ -180,8 +213,9 @@ class NativeVideoViewerPage extends HookConsumerWidget {
|
|||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
behavior: HitTestBehavior.deferToChild,
|
behavior: HitTestBehavior.deferToChild,
|
||||||
child: PopScope(
|
child: PopScope(
|
||||||
onPopInvokedWithResult: (didPop, _) =>
|
onPopInvokedWithResult: (didPop, _) => ref
|
||||||
updatePlayback(VideoPlaybackValue.uninitialized()),
|
.read(videoPlaybackValueProvider.notifier)
|
||||||
|
.value = VideoPlaybackValue.uninitialized(),
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: size.height,
|
height: size.height,
|
||||||
width: size.width,
|
width: size.width,
|
||||||
|
@ -87,6 +87,20 @@ class VideoPlaybackValue {
|
|||||||
volume: 0.0,
|
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,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final videoPlaybackValueProvider =
|
final videoPlaybackValueProvider =
|
||||||
|
Loading…
x
Reference in New Issue
Block a user