Skip to content

Commit

Permalink
fix(mobile): video player disposes early (immich-app#2275)
Browse files Browse the repository at this point in the history
* fix(mobile): video player disposes early

* fixed show download button based on asset state

* style icon size

* disable screensleep on video player

* better position for video

* better scroll physics on iOS
  • Loading branch information
alextran1502 authored Apr 18, 2023
1 parent 8a45c25 commit c8d3fae
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 35 deletions.
10 changes: 9 additions & 1 deletion mobile/lib/modules/asset_viewer/ui/top_control_app_bar.dart
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class TopControlAppBar extends HookConsumerWidget {

@override
Widget build(BuildContext context, WidgetRef ref) {
const double iconSize = 18.0;
const double iconSize = 22.0;

Widget buildFavoriteButton() {
return IconButton(
Expand Down Expand Up @@ -82,6 +82,14 @@ class TopControlAppBar extends HookConsumerWidget {
color: Colors.grey[200],
),
),
if (asset.storage == AssetState.merged)
IconButton(
onPressed: onDownloadPressed,
icon: Icon(
Icons.cloud_download_outlined,
color: Colors.grey[200],
),
),
if (asset.isRemote)
IconButton(
onPressed: () {
Expand Down
6 changes: 4 additions & 2 deletions mobile/lib/modules/asset_viewer/views/gallery_viewer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,8 @@ class GalleryViewerPage extends HookConsumerWidget {
onFavorite: () {
toggleFavorite(assetList[indexOfAsset.value]);
},
onDownloadPressed: assetList[indexOfAsset.value].isLocal
onDownloadPressed: assetList[indexOfAsset.value].storage ==
AssetState.local
? null
: () {
ref.watch(imageViewerStateProvider.notifier).downloadAsset(
Expand Down Expand Up @@ -391,7 +392,7 @@ class GalleryViewerPage extends HookConsumerWidget {
scrollPhysics: isZoomed.value
? const NeverScrollableScrollPhysics() // Don't allow paging while scrolled in
: (Platform.isIOS
? const BouncingScrollPhysics() // Use bouncing physics for iOS
? const ScrollPhysics() // Use bouncing physics for iOS
: const ClampingScrollPhysics() // Use heavy physics for Android
),
itemCount: assetList.length,
Expand Down Expand Up @@ -516,6 +517,7 @@ class GalleryViewerPage extends HookConsumerWidget {
filterQuality: FilterQuality.high,
maxScale: 1.0,
minScale: 1.0,
basePosition: Alignment.bottomCenter,
child: SafeArea(
child: VideoViewerPage(
onPlaying: () => isPlayingVideo.value = true,
Expand Down
70 changes: 38 additions & 32 deletions mobile/lib/modules/asset_viewer/views/video_viewer_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,10 @@ class VideoViewerPage extends HookConsumerWidget {

@override
Widget build(BuildContext context, WidgetRef ref) {
if (asset.isLocal) {
if (asset.storage == AssetState.local && asset.livePhotoVideoId == null) {
final AsyncValue<File> videoFile = ref.watch(_fileFamily(asset.local!));
return videoFile.when(
data: (data) => VideoThumbnailPlayer(
data: (data) => VideoPlayer(
file: data,
isMotionVideo: false,
onVideoEnded: () {},
Expand All @@ -59,7 +59,7 @@ class VideoViewerPage extends HookConsumerWidget {

return Stack(
children: [
VideoThumbnailPlayer(
VideoPlayer(
url: videoUrl,
jwtToken: Store.get(StoreKey.accessToken),
isMotionVideo: isMotionVideo,
Expand All @@ -85,7 +85,7 @@ final _fileFamily =
return file;
});

class VideoThumbnailPlayer extends StatefulWidget {
class VideoPlayer extends StatefulWidget {
final String? url;
final String? jwtToken;
final File? file;
Expand All @@ -95,7 +95,7 @@ class VideoThumbnailPlayer extends StatefulWidget {
final Function()? onPlaying;
final Function()? onPaused;

const VideoThumbnailPlayer({
const VideoPlayer({
Key? key,
this.url,
this.jwtToken,
Expand All @@ -107,10 +107,10 @@ class VideoThumbnailPlayer extends StatefulWidget {
}) : super(key: key);

@override
State<VideoThumbnailPlayer> createState() => _VideoThumbnailPlayerState();
State<VideoPlayer> createState() => _VideoPlayerState();
}

class _VideoThumbnailPlayerState extends State<VideoThumbnailPlayer> {
class _VideoPlayerState extends State<VideoPlayer> {
late VideoPlayerController videoPlayerController;
ChewieController? chewieController;

Expand All @@ -120,14 +120,17 @@ class _VideoThumbnailPlayerState extends State<VideoThumbnailPlayer> {
initializePlayer();

videoPlayerController.addListener(() {
if (videoPlayerController.value.isPlaying) {
widget.onPlaying?.call();
} else if (!videoPlayerController.value.isPlaying) {
widget.onPaused?.call();
}
if (videoPlayerController.value.position ==
videoPlayerController.value.duration) {
widget.onVideoEnded();
if (videoPlayerController.value.isInitialized) {
if (videoPlayerController.value.isPlaying) {
widget.onPlaying?.call();
} else if (!videoPlayerController.value.isPlaying) {
widget.onPaused?.call();
}

if (videoPlayerController.value.position ==
videoPlayerController.value.duration) {
widget.onVideoEnded();
}
}
});
}
Expand All @@ -145,21 +148,22 @@ class _VideoThumbnailPlayerState extends State<VideoThumbnailPlayer> {
_createChewieController();
setState(() {});
} catch (e) {
debugPrint("ERROR initialize video player");
debugPrint("ERROR initialize video player $e");
}
}

_createChewieController() {
chewieController = ChewieController(
controlsSafeAreaMinimum: const EdgeInsets.only(
bottom: 156,
bottom: 100,
),
showOptions: true,
showControlsOnInitialize: false,
videoPlayerController: videoPlayerController,
autoPlay: true,
autoInitialize: true,
allowFullScreen: true,
allowedScreenSleep: false,
showControls: !widget.isMotionVideo,
hideControlsTimer: const Duration(seconds: 5),
);
Expand All @@ -175,20 +179,22 @@ class _VideoThumbnailPlayerState extends State<VideoThumbnailPlayer> {

@override
Widget build(BuildContext context) {
return chewieController?.videoPlayerController.value.isInitialized == true
? SizedBox(
child: Chewie(
controller: chewieController!,
),
)
: const Center(
child: SizedBox(
width: 75,
height: 75,
child: CircularProgressIndicator.adaptive(
strokeWidth: 2,
),
),
);
if (chewieController?.videoPlayerController.value.isInitialized == true) {
return SizedBox(
child: Chewie(
controller: chewieController!,
),
);
} else {
return const Center(
child: SizedBox(
width: 75,
height: 75,
child: CircularProgressIndicator.adaptive(
strokeWidth: 2,
),
),
);
}
}
}
2 changes: 2 additions & 0 deletions mobile/lib/shared/models/asset.dart
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,8 @@ class Asset {
"fileName": "$fileName",
"isFavorite": $isFavorite,
"isLocal": $isLocal,
"isRemote: $isRemote,
"storage": $storage,
"width": ${width ?? "N/A"},
"height": ${height ?? "N/A"},
"isArchived": $isArchived
Expand Down

0 comments on commit c8d3fae

Please sign in to comment.