-
Notifications
You must be signed in to change notification settings - Fork 2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor(mobile): Use hooks to manage Chewie controller for video (#7008
) * video loading delayed * Chewie controller implemented in hook * fixing look and feel * Finalizing delay and animations * Fixes issue with immersive mode showing immediately in videos * format fix * Fixes bug where video controls would hide immediately after showing while playing and reverts hide controls timer to 5 seconds * Fixed rebase issues --------- Co-authored-by: Alex Tran <alex.tran1502@gmail.com>
- Loading branch information
1 parent
a1108c0
commit 816050b
Showing
8 changed files
with
311 additions
and
236 deletions.
There are no files selected for viewing
179 changes: 179 additions & 0 deletions
179
mobile/lib/modules/asset_viewer/hooks/chewiew_controller_hook.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,179 @@ | ||
import 'dart:async'; | ||
|
||
import 'package:chewie/chewie.dart'; | ||
import 'package:flutter/material.dart'; | ||
import 'package:flutter_hooks/flutter_hooks.dart'; | ||
import 'package:immich_mobile/shared/models/asset.dart'; | ||
import 'package:immich_mobile/shared/models/store.dart'; | ||
import 'package:video_player/video_player.dart'; | ||
import 'package:immich_mobile/shared/models/store.dart' as store; | ||
import 'package:wakelock_plus/wakelock_plus.dart'; | ||
|
||
/// Provides the initialized video player controller | ||
/// If the asset is local, use the local file | ||
/// Otherwise, use a video player with a URL | ||
ChewieController? useChewieController( | ||
Asset asset, { | ||
EdgeInsets controlsSafeAreaMinimum = const EdgeInsets.only( | ||
bottom: 100, | ||
), | ||
bool showOptions = true, | ||
bool showControlsOnInitialize = false, | ||
bool autoPlay = true, | ||
bool autoInitialize = true, | ||
bool allowFullScreen = false, | ||
bool allowedScreenSleep = false, | ||
bool showControls = true, | ||
Widget? customControls, | ||
Widget? placeholder, | ||
Duration hideControlsTimer = const Duration(seconds: 1), | ||
VoidCallback? onPlaying, | ||
VoidCallback? onPaused, | ||
VoidCallback? onVideoEnded, | ||
}) { | ||
return use( | ||
_ChewieControllerHook( | ||
asset: asset, | ||
placeholder: placeholder, | ||
showOptions: showOptions, | ||
controlsSafeAreaMinimum: controlsSafeAreaMinimum, | ||
autoPlay: autoPlay, | ||
allowFullScreen: allowFullScreen, | ||
customControls: customControls, | ||
hideControlsTimer: hideControlsTimer, | ||
showControlsOnInitialize: showControlsOnInitialize, | ||
showControls: showControls, | ||
autoInitialize: autoInitialize, | ||
allowedScreenSleep: allowedScreenSleep, | ||
onPlaying: onPlaying, | ||
onPaused: onPaused, | ||
onVideoEnded: onVideoEnded, | ||
), | ||
); | ||
} | ||
|
||
class _ChewieControllerHook extends Hook<ChewieController?> { | ||
final Asset asset; | ||
final EdgeInsets controlsSafeAreaMinimum; | ||
final bool showOptions; | ||
final bool showControlsOnInitialize; | ||
final bool autoPlay; | ||
final bool autoInitialize; | ||
final bool allowFullScreen; | ||
final bool allowedScreenSleep; | ||
final bool showControls; | ||
final Widget? customControls; | ||
final Widget? placeholder; | ||
final Duration hideControlsTimer; | ||
final VoidCallback? onPlaying; | ||
final VoidCallback? onPaused; | ||
final VoidCallback? onVideoEnded; | ||
|
||
const _ChewieControllerHook({ | ||
required this.asset, | ||
this.controlsSafeAreaMinimum = const EdgeInsets.only( | ||
bottom: 100, | ||
), | ||
this.showOptions = true, | ||
this.showControlsOnInitialize = false, | ||
this.autoPlay = true, | ||
this.autoInitialize = true, | ||
this.allowFullScreen = false, | ||
this.allowedScreenSleep = false, | ||
this.showControls = true, | ||
this.customControls, | ||
this.placeholder, | ||
this.hideControlsTimer = const Duration(seconds: 3), | ||
this.onPlaying, | ||
this.onPaused, | ||
this.onVideoEnded, | ||
}); | ||
|
||
@override | ||
createState() => _ChewieControllerHookState(); | ||
} | ||
|
||
class _ChewieControllerHookState | ||
extends HookState<ChewieController?, _ChewieControllerHook> { | ||
ChewieController? chewieController; | ||
VideoPlayerController? videoPlayerController; | ||
|
||
@override | ||
void initHook() async { | ||
super.initHook(); | ||
unawaited(_initialize()); | ||
} | ||
|
||
@override | ||
void dispose() { | ||
chewieController?.dispose(); | ||
videoPlayerController?.dispose(); | ||
super.dispose(); | ||
} | ||
|
||
@override | ||
ChewieController? build(BuildContext context) { | ||
return chewieController; | ||
} | ||
|
||
/// Initializes the chewie controller and video player controller | ||
Future<void> _initialize() async { | ||
if (hook.asset.isLocal && hook.asset.livePhotoVideoId == null) { | ||
// Use a local file for the video player controller | ||
final file = await hook.asset.local!.file; | ||
if (file == null) { | ||
throw Exception('No file found for the video'); | ||
} | ||
videoPlayerController = VideoPlayerController.file(file); | ||
} else { | ||
// Use a network URL for the video player controller | ||
final serverEndpoint = store.Store.get(store.StoreKey.serverEndpoint); | ||
final String videoUrl = hook.asset.livePhotoVideoId != null | ||
? '$serverEndpoint/asset/file/${hook.asset.livePhotoVideoId}' | ||
: '$serverEndpoint/asset/file/${hook.asset.remoteId}'; | ||
|
||
final url = Uri.parse(videoUrl); | ||
final accessToken = store.Store.get(StoreKey.accessToken); | ||
|
||
videoPlayerController = VideoPlayerController.networkUrl( | ||
url, | ||
httpHeaders: {"x-immich-user-token": accessToken}, | ||
); | ||
} | ||
|
||
videoPlayerController!.addListener(() { | ||
final value = videoPlayerController!.value; | ||
if (value.isPlaying) { | ||
WakelockPlus.enable(); | ||
hook.onPlaying?.call(); | ||
} else if (!value.isPlaying) { | ||
WakelockPlus.disable(); | ||
hook.onPaused?.call(); | ||
} | ||
|
||
if (value.position == value.duration) { | ||
WakelockPlus.disable(); | ||
hook.onVideoEnded?.call(); | ||
} | ||
}); | ||
|
||
await videoPlayerController!.initialize(); | ||
|
||
setState(() { | ||
chewieController = ChewieController( | ||
videoPlayerController: videoPlayerController!, | ||
controlsSafeAreaMinimum: hook.controlsSafeAreaMinimum, | ||
showOptions: hook.showOptions, | ||
showControlsOnInitialize: hook.showControlsOnInitialize, | ||
autoPlay: hook.autoPlay, | ||
autoInitialize: hook.autoInitialize, | ||
allowFullScreen: hook.allowFullScreen, | ||
allowedScreenSleep: hook.allowedScreenSleep, | ||
showControls: hook.showControls, | ||
customControls: hook.customControls, | ||
placeholder: hook.placeholder, | ||
hideControlsTimer: hook.hideControlsTimer, | ||
); | ||
}); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.