mirror of
https://github.com/immich-app/immich.git
synced 2025-03-11 02:23:09 -05:00
separate video loader widget
This commit is contained in:
parent
338e5a8e5c
commit
7ed2c68c46
3 changed files with 79 additions and 47 deletions
|
@ -33,25 +33,28 @@ class NativeVideoLoader extends HookConsumerWidget {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final log = Logger('NativeVideoLoader');
|
||||
log.info('Building NativeVideoLoader');
|
||||
// fast path for aspect ratio
|
||||
final initAspectRatio = useMemoized(
|
||||
() {
|
||||
if (asset.exifInfo == null) {
|
||||
return null;
|
||||
}
|
||||
// final initAspectRatio = useMemoized(
|
||||
// () {
|
||||
// if (asset.exifInfo == null) {
|
||||
// return null;
|
||||
// }
|
||||
|
||||
final width = asset.orientatedWidth?.toDouble();
|
||||
final height = asset.orientatedHeight?.toDouble();
|
||||
return width != null && height != null && width > 0 && height > 0
|
||||
? width / height
|
||||
: null;
|
||||
},
|
||||
);
|
||||
// final width = asset.orientatedWidth?.toDouble();
|
||||
// final height = asset.orientatedHeight?.toDouble();
|
||||
// return width != null && height != null && width > 0 && height > 0
|
||||
// ? width / height
|
||||
// : null;
|
||||
// },
|
||||
// );
|
||||
|
||||
final localEntity = useMemoized(
|
||||
() => asset.localId != null ? AssetEntity.fromId(asset.localId!) : null,
|
||||
() => asset.isLocal ? AssetEntity.fromId(asset.localId!) : null,
|
||||
);
|
||||
Future<double> calculateAspectRatio() async {
|
||||
log.info('Calculating aspect ratio');
|
||||
late final double? orientatedWidth;
|
||||
late final double? orientatedHeight;
|
||||
|
||||
|
@ -68,6 +71,7 @@ class NativeVideoLoader extends HookConsumerWidget {
|
|||
orientatedHeight = entity.orientatedHeight?.toDouble();
|
||||
}
|
||||
|
||||
log.info('Calculated aspect ratio');
|
||||
if (orientatedWidth != null &&
|
||||
orientatedHeight != null &&
|
||||
orientatedWidth > 0 &&
|
||||
|
@ -78,12 +82,7 @@ class NativeVideoLoader extends HookConsumerWidget {
|
|||
return 1.0;
|
||||
}
|
||||
|
||||
final aspectRatioFuture = useMemoized(
|
||||
() => initAspectRatio == null ? calculateAspectRatio() : null,
|
||||
);
|
||||
|
||||
final log = Logger('NativeVideoLoader');
|
||||
log.info('Building NativeVideoLoader');
|
||||
final aspectRatioFuture = useMemoized(() => calculateAspectRatio());
|
||||
|
||||
Future<VideoSource> createLocalSource() async {
|
||||
log.info('Loading video from local storage');
|
||||
|
@ -97,10 +96,12 @@ class NativeVideoLoader extends HookConsumerWidget {
|
|||
throw Exception('No file found for the video');
|
||||
}
|
||||
|
||||
return await VideoSource.init(
|
||||
final source = await VideoSource.init(
|
||||
path: file.path,
|
||||
type: VideoSourceType.file,
|
||||
);
|
||||
log.info('Loaded video from local storage');
|
||||
return source;
|
||||
}
|
||||
|
||||
Future<VideoSource> createRemoteSource() async {
|
||||
|
@ -112,14 +113,16 @@ class NativeVideoLoader extends HookConsumerWidget {
|
|||
? '$serverEndpoint/assets/${asset.livePhotoVideoId}/video/playback'
|
||||
: '$serverEndpoint/assets/${asset.remoteId}/video/playback';
|
||||
|
||||
return await VideoSource.init(
|
||||
final source = await VideoSource.init(
|
||||
path: videoUrl,
|
||||
type: VideoSourceType.network,
|
||||
headers: ApiService.getRequestHeaders(),
|
||||
);
|
||||
log.info('Loaded video from server');
|
||||
return source;
|
||||
}
|
||||
|
||||
Future<VideoSource> createSource(Asset asset) async {
|
||||
Future<VideoSource> createSource() {
|
||||
if (asset.isLocal && asset.livePhotoVideoId == null) {
|
||||
return createLocalSource();
|
||||
}
|
||||
|
@ -127,6 +130,16 @@ class NativeVideoLoader extends HookConsumerWidget {
|
|||
return createRemoteSource();
|
||||
}
|
||||
|
||||
final createSourceFuture = useMemoized(() => createSource());
|
||||
|
||||
final combinedFuture = useMemoized(
|
||||
() async {
|
||||
final aspectRatio = await aspectRatioFuture;
|
||||
final source = await createSourceFuture;
|
||||
return (source, aspectRatio);
|
||||
},
|
||||
);
|
||||
|
||||
final size = MediaQuery.sizeOf(context);
|
||||
|
||||
return SizedBox(
|
||||
|
@ -143,18 +156,17 @@ class NativeVideoLoader extends HookConsumerWidget {
|
|||
width: size.width,
|
||||
child: FutureBuilder(
|
||||
key: ValueKey(asset.id),
|
||||
future: aspectRatioFuture,
|
||||
initialData: initAspectRatio,
|
||||
future: combinedFuture,
|
||||
// initialData: initAspectRatio,
|
||||
builder: (context, snapshot) {
|
||||
if (!snapshot.hasData) {
|
||||
return placeholder;
|
||||
}
|
||||
|
||||
return NativeVideoViewerPage(
|
||||
key: ValueKey(asset.id),
|
||||
videoSource: createSource(asset),
|
||||
videoSource: snapshot.data!.$1,
|
||||
duration: asset.duration,
|
||||
aspectRatio: snapshot.data as double,
|
||||
aspectRatio: snapshot.data!.$2,
|
||||
isMotionVideo: isMotionVideo,
|
||||
hideControlsTimer: hideControlsTimer,
|
||||
loopVideo: loopVideo,
|
||||
|
|
|
@ -30,7 +30,7 @@ import 'package:wakelock_plus/wakelock_plus.dart';
|
|||
// }
|
||||
|
||||
class NativeVideoViewerPage extends HookConsumerWidget {
|
||||
final Future<VideoSource> videoSource;
|
||||
final VideoSource videoSource;
|
||||
final double aspectRatio;
|
||||
final Duration duration;
|
||||
final bool isMotionVideo;
|
||||
|
@ -75,7 +75,7 @@ class NativeVideoViewerPage extends HookConsumerWidget {
|
|||
}
|
||||
|
||||
// timer to mark videos as buffering if the position does not change
|
||||
useInterval(const Duration(seconds: 5), checkIfBuffering);
|
||||
// useInterval(const Duration(seconds: 5), checkIfBuffering);
|
||||
|
||||
// When the volume changes, set the volume
|
||||
ref.listen(videoPlayerControlsProvider.select((value) => value.mute),
|
||||
|
@ -186,12 +186,12 @@ class NativeVideoViewerPage extends HookConsumerWidget {
|
|||
if (state == VideoPlaybackState.playing) {
|
||||
log.info('Syncing with the controls playing');
|
||||
// Sync with the controls playing
|
||||
WakelockPlus.enable();
|
||||
// WakelockPlus.enable();
|
||||
log.info('Synced with the controls playing');
|
||||
} else {
|
||||
log.info('Syncing with the controls pause');
|
||||
// Sync with the controls pause
|
||||
WakelockPlus.disable();
|
||||
// WakelockPlus.disable();
|
||||
log.info('Synced with the controls pause');
|
||||
}
|
||||
}
|
||||
|
@ -233,7 +233,7 @@ class NativeVideoViewerPage extends HookConsumerWidget {
|
|||
log.info('initController: added onPlaybackEnded listener');
|
||||
|
||||
log.info('initController: loading video source');
|
||||
nc.loadVideoSource(await videoSource);
|
||||
nc.loadVideoSource(videoSource);
|
||||
log.info('initController: loaded video source');
|
||||
|
||||
log.info('initController: setting controller');
|
||||
|
@ -280,26 +280,24 @@ class NativeVideoViewerPage extends HookConsumerWidget {
|
|||
playerController.onPlaybackEnded.removeListener(onPlaybackEnded);
|
||||
log.info('Removed onPlaybackEnded listener');
|
||||
|
||||
Future.microtask(() async {
|
||||
log.info('Stopping video');
|
||||
await playerController.stop();
|
||||
log.info('Stopped video');
|
||||
|
||||
log.info('Disabling wakelock');
|
||||
await WakelockPlus.disable();
|
||||
log.info('Disabled wakelock');
|
||||
});
|
||||
log.info('Stopping video');
|
||||
playerController.stop();
|
||||
log.info('Stopped video');
|
||||
|
||||
log.info('Disposing controller');
|
||||
controller.value = null;
|
||||
log.info('Disposed controller');
|
||||
|
||||
// log.info('Disabling Wakelock');
|
||||
// WakelockPlus.disable();
|
||||
// log.info('Disabled Wakelock');
|
||||
} catch (error) {
|
||||
log.severe('Error during useEffect cleanup: $error');
|
||||
// Consume error from the controller
|
||||
}
|
||||
};
|
||||
},
|
||||
[],
|
||||
[videoSource],
|
||||
);
|
||||
|
||||
return Stack(
|
||||
|
|
|
@ -36,6 +36,10 @@ class VideoPlayerControls extends StateNotifier<VideoPlaybackControls> {
|
|||
}
|
||||
|
||||
void reset() {
|
||||
if (state.position == 0 && !state.mute && !state.pause) {
|
||||
return;
|
||||
}
|
||||
|
||||
state = VideoPlaybackControls(
|
||||
position: 0,
|
||||
pause: false,
|
||||
|
@ -47,6 +51,10 @@ class VideoPlayerControls extends StateNotifier<VideoPlaybackControls> {
|
|||
bool get mute => state.mute;
|
||||
|
||||
set position(double value) {
|
||||
if (state.position == value) {
|
||||
return;
|
||||
}
|
||||
|
||||
state = VideoPlaybackControls(
|
||||
position: value,
|
||||
mute: state.mute,
|
||||
|
@ -55,6 +63,10 @@ class VideoPlayerControls extends StateNotifier<VideoPlaybackControls> {
|
|||
}
|
||||
|
||||
set mute(bool value) {
|
||||
if (state.mute == value) {
|
||||
return;
|
||||
}
|
||||
|
||||
state = VideoPlaybackControls(
|
||||
position: state.position,
|
||||
mute: value,
|
||||
|
@ -71,6 +83,10 @@ class VideoPlayerControls extends StateNotifier<VideoPlaybackControls> {
|
|||
}
|
||||
|
||||
void pause() {
|
||||
if (state.pause) {
|
||||
return;
|
||||
}
|
||||
|
||||
state = VideoPlaybackControls(
|
||||
position: state.position,
|
||||
mute: state.mute,
|
||||
|
@ -79,6 +95,10 @@ class VideoPlayerControls extends StateNotifier<VideoPlaybackControls> {
|
|||
}
|
||||
|
||||
void play() {
|
||||
if (!state.pause) {
|
||||
return;
|
||||
}
|
||||
|
||||
state = VideoPlaybackControls(
|
||||
position: state.position,
|
||||
mute: state.mute,
|
||||
|
@ -95,11 +115,13 @@ class VideoPlayerControls extends StateNotifier<VideoPlaybackControls> {
|
|||
}
|
||||
|
||||
void restart() {
|
||||
state = VideoPlaybackControls(
|
||||
position: 0,
|
||||
mute: state.mute,
|
||||
pause: true,
|
||||
);
|
||||
if (state.position > 0 || !state.pause) {
|
||||
state = VideoPlaybackControls(
|
||||
position: 0,
|
||||
mute: state.mute,
|
||||
pause: false,
|
||||
);
|
||||
}
|
||||
|
||||
state = VideoPlaybackControls(
|
||||
position: 0,
|
||||
|
|
Loading…
Add table
Reference in a new issue