1
0
Fork 0
mirror of https://github.com/immich-app/immich.git synced 2025-01-01 08:31:59 +00:00

fix controls when swiping between image and video

This commit is contained in:
mertalev 2024-11-09 00:31:10 -05:00
parent 190dbb0042
commit 0010eda67f
No known key found for this signature in database
GPG key ID: CA85EF6600C9E8AD
6 changed files with 51 additions and 45 deletions

View file

@ -168,6 +168,9 @@ class Asset {
@ignore @ignore
bool get isImage => type == AssetType.image; bool get isImage => type == AssetType.image;
@ignore
bool get isVideo => type == AssetType.video;
@ignore @ignore
bool get isMotionPhoto => livePhotoVideoId != null; bool get isMotionPhoto => livePhotoVideoId != null;

View file

@ -79,10 +79,8 @@ class GalleryViewerPage extends HookConsumerWidget {
ref.listen( ref.listen(
videoPlaybackValueProvider.select( videoPlaybackValueProvider.select(
(playback) => playback.state == VideoPlaybackState.playing, (playback) => playback.state == VideoPlaybackState.playing,
), (wasPlaying, isPlaying) { ), (_, isPlaying) {
if (wasPlaying != null && wasPlaying && !isPlaying) { isPlayingMotionVideo.value = isPlaying;
isPlayingMotionVideo.value = false;
}
}); });
} }
@ -271,11 +269,13 @@ class GalleryViewerPage extends HookConsumerWidget {
onTapDown: (_, __, ___) { onTapDown: (_, __, ___) {
ref.read(showControlsProvider.notifier).toggle(); ref.read(showControlsProvider.notifier).toggle();
}, },
onLongPressStart: (_, __, ___) { onLongPressStart: asset.isMotionPhoto
if (asset.livePhotoVideoId != null) { ? (_, __, ___) {
isPlayingMotionVideo.value = true; if (asset.isMotionPhoto) {
} isPlayingMotionVideo.value = true;
}, }
}
: null,
imageProvider: ImmichImage.imageProvider(asset: asset), imageProvider: ImmichImage.imageProvider(asset: asset),
heroAttributes: PhotoViewHeroAttributes( heroAttributes: PhotoViewHeroAttributes(
tag: getHeroTag(asset), tag: getHeroTag(asset),
@ -336,10 +336,6 @@ class GalleryViewerPage extends HookConsumerWidget {
PhotoViewGalleryPageOptions buildAsset(BuildContext context, int index) { PhotoViewGalleryPageOptions buildAsset(BuildContext context, int index) {
final newAsset = index == currentIndex.value ? asset : loadAsset(index); final newAsset = index == currentIndex.value ? asset : loadAsset(index);
if (newAsset.isImage) {
ref.read(showControlsProvider.notifier).show = false;
}
if (newAsset.isImage && !isPlayingMotionVideo.value) { if (newAsset.isImage && !isPlayingMotionVideo.value) {
return buildImage(context, newAsset); return buildImage(context, newAsset);
} }
@ -357,8 +353,11 @@ class GalleryViewerPage extends HookConsumerWidget {
PhotoViewGallery.builder( PhotoViewGallery.builder(
key: ValueKey(asset), key: ValueKey(asset),
scaleStateChangedCallback: (state) { scaleStateChangedCallback: (state) {
isZoomed.value = state != PhotoViewScaleState.initial; if (asset.isImage && !isPlayingMotionVideo.value) {
ref.read(showControlsProvider.notifier).show = !isZoomed.value; isZoomed.value = state != PhotoViewScaleState.initial;
ref.read(showControlsProvider.notifier).show =
!isZoomed.value;
}
}, },
// wantKeepAlive: true, // wantKeepAlive: true,
gaplessPlayback: true, gaplessPlayback: true,
@ -396,15 +395,15 @@ class GalleryViewerPage extends HookConsumerWidget {
final newAsset = final newAsset =
value == currentIndex.value ? asset : loadAsset(value); value == currentIndex.value ? asset : loadAsset(value);
if (!newAsset.isImage || newAsset.isMotionPhoto) {
ref.read(videoPlaybackValueProvider.notifier).reset();
}
currentIndex.value = value; currentIndex.value = value;
stackIndex.value = -1; stackIndex.value = -1;
isPlayingMotionVideo.value = false; isPlayingMotionVideo.value = false;
ref.read(currentAssetProvider.notifier).set(newAsset); ref.read(currentAssetProvider.notifier).set(newAsset);
if (newAsset.isVideo || newAsset.isMotionPhoto) {
ref.read(videoPlaybackValueProvider.notifier).reset();
}
// Wait for page change animation to finish, then precache the next image // Wait for page change animation to finish, then precache the next image
Timer(const Duration(milliseconds: 400), () { Timer(const Duration(milliseconds: 400), () {
@ -418,11 +417,8 @@ class GalleryViewerPage extends HookConsumerWidget {
left: 0, left: 0,
right: 0, right: 0,
child: GalleryAppBar( child: GalleryAppBar(
asset: asset,
showInfo: showInfo, showInfo: showInfo,
isPlayingVideo: isPlayingMotionVideo.value, isPlayingMotionVideo: isPlayingMotionVideo,
onToggleMotionVideo: () =>
isPlayingMotionVideo.value = !isPlayingMotionVideo.value,
), ),
), ),
Positioned( Positioned(
@ -444,10 +440,7 @@ class GalleryViewerPage extends HookConsumerWidget {
controller: controller, controller: controller,
showStack: showStack, showStack: showStack,
stackIndex: stackIndex.value, stackIndex: stackIndex.value,
asset: asset,
assetIndex: currentIndex, assetIndex: currentIndex,
showVideoPlayerControls:
!asset.isImage && !asset.isMotionPhoto,
), ),
], ],
), ),

View file

@ -184,8 +184,8 @@ class NativeVideoViewerPage extends HookConsumerWidget {
try { try {
if (mute && playbackInfo.volume != 0.0) { if (mute && playbackInfo.volume != 0.0) {
await playerController.setVolume(0.0); await playerController.setVolume(0.0);
} else if (!mute && playbackInfo.volume != 0.7) { } else if (!mute && playbackInfo.volume != 0.9) {
await playerController.setVolume(0.7); await playerController.setVolume(0.9);
} }
} catch (error) { } catch (error) {
log.severe('Error setting volume: $error'); log.severe('Error setting volume: $error');

View file

@ -10,6 +10,7 @@ import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/providers/album/album.provider.dart'; import 'package:immich_mobile/providers/album/album.provider.dart';
import 'package:immich_mobile/providers/album/current_album.provider.dart'; import 'package:immich_mobile/providers/album/current_album.provider.dart';
import 'package:immich_mobile/providers/asset_viewer/asset_stack.provider.dart'; import 'package:immich_mobile/providers/asset_viewer/asset_stack.provider.dart';
import 'package:immich_mobile/providers/asset_viewer/current_asset.provider.dart';
import 'package:immich_mobile/providers/asset_viewer/download.provider.dart'; import 'package:immich_mobile/providers/asset_viewer/download.provider.dart';
import 'package:immich_mobile/providers/asset_viewer/show_controls.provider.dart'; import 'package:immich_mobile/providers/asset_viewer/show_controls.provider.dart';
import 'package:immich_mobile/services/stack.service.dart'; import 'package:immich_mobile/services/stack.service.dart';
@ -26,12 +27,10 @@ import 'package:immich_mobile/widgets/common/immich_toast.dart';
import 'package:immich_mobile/pages/editing/edit.page.dart'; import 'package:immich_mobile/pages/editing/edit.page.dart';
class BottomGalleryBar extends ConsumerWidget { class BottomGalleryBar extends ConsumerWidget {
final Asset asset;
final ValueNotifier<int> assetIndex; final ValueNotifier<int> assetIndex;
final bool showStack; final bool showStack;
final int stackIndex; final int stackIndex;
final ValueNotifier<int> totalAssets; final ValueNotifier<int> totalAssets;
final bool showVideoPlayerControls;
final PageController controller; final PageController controller;
final RenderList renderList; final RenderList renderList;
@ -39,17 +38,20 @@ class BottomGalleryBar extends ConsumerWidget {
super.key, super.key,
required this.showStack, required this.showStack,
required this.stackIndex, required this.stackIndex,
required this.asset,
required this.assetIndex, required this.assetIndex,
required this.controller, required this.controller,
required this.totalAssets, required this.totalAssets,
required this.showVideoPlayerControls,
required this.renderList, required this.renderList,
}); });
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
final asset = ref.watch(currentAssetProvider);
if (asset == null) {
return const SizedBox();
}
final isOwner = asset.ownerId == ref.watch(currentUserProvider)?.isarId; final isOwner = asset.ownerId == ref.watch(currentUserProvider)?.isarId;
final showControls = ref.watch(showControlsProvider);
final stackItems = showStack && asset.stackCount > 0 final stackItems = showStack && asset.stackCount > 0
? ref.watch(assetStackStateProvider(asset)) ? ref.watch(assetStackStateProvider(asset))
@ -324,7 +326,7 @@ class BottomGalleryBar extends ConsumerWidget {
}, },
]; ];
return IgnorePointer( return IgnorePointer(
ignoring: !ref.watch(showControlsProvider), ignoring: !showControls,
child: AnimatedOpacity( child: AnimatedOpacity(
duration: const Duration(milliseconds: 100), duration: const Duration(milliseconds: 100),
opacity: ref.watch(showControlsProvider) ? 1.0 : 0.0, opacity: ref.watch(showControlsProvider) ? 1.0 : 0.0,
@ -341,7 +343,7 @@ class BottomGalleryBar extends ConsumerWidget {
padding: EdgeInsets.only(top: 40.0), padding: EdgeInsets.only(top: 40.0),
child: Column( child: Column(
children: [ children: [
if (showVideoPlayerControls) const VideoControls(), if (asset.isVideo) const VideoControls(),
BottomNavigationBar( BottomNavigationBar(
elevation: 0.0, elevation: 0.0,
backgroundColor: Colors.transparent, backgroundColor: Colors.transparent,

View file

@ -17,10 +17,15 @@ class CustomVideoPlayerControls extends HookConsumerWidget {
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
final showControls = ref.watch(showControlsProvider);
// A timer to hide the controls // A timer to hide the controls
final hideTimer = useTimer( final hideTimer = useTimer(
hideTimerDuration, hideTimerDuration,
() { () {
if (!context.mounted) {
return;
}
final state = ref.read(videoPlaybackValueProvider).state; final state = ref.read(videoPlaybackValueProvider).state;
// Do not hide on paused // Do not hide on paused
if (state != VideoPlaybackState.paused) { if (state != VideoPlaybackState.paused) {
@ -66,7 +71,7 @@ class CustomVideoPlayerControls extends HookConsumerWidget {
behavior: HitTestBehavior.opaque, behavior: HitTestBehavior.opaque,
onTap: showControlsAndStartHideTimer, onTap: showControlsAndStartHideTimer,
child: AbsorbPointer( child: AbsorbPointer(
absorbing: !ref.watch(showControlsProvider), absorbing: !showControls,
child: Stack( child: Stack(
children: [ children: [
if (showBuffering) if (showBuffering)
@ -84,7 +89,7 @@ class CustomVideoPlayerControls extends HookConsumerWidget {
iconColor: Colors.white, iconColor: Colors.white,
isFinished: state == VideoPlaybackState.completed, isFinished: state == VideoPlaybackState.completed,
isPlaying: state == VideoPlaybackState.playing, isPlaying: state == VideoPlaybackState.playing,
show: ref.watch(showControlsProvider), show: showControls,
onPressed: togglePlay, onPressed: togglePlay,
), ),
), ),

View file

@ -4,6 +4,7 @@ import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart'; import 'package:fluttertoast/fluttertoast.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/providers/album/current_album.provider.dart'; import 'package:immich_mobile/providers/album/current_album.provider.dart';
import 'package:immich_mobile/providers/asset_viewer/current_asset.provider.dart';
import 'package:immich_mobile/widgets/album/add_to_album_bottom_sheet.dart'; import 'package:immich_mobile/widgets/album/add_to_album_bottom_sheet.dart';
import 'package:immich_mobile/providers/asset_viewer/download.provider.dart'; import 'package:immich_mobile/providers/asset_viewer/download.provider.dart';
import 'package:immich_mobile/providers/asset_viewer/show_controls.provider.dart'; import 'package:immich_mobile/providers/asset_viewer/show_controls.provider.dart';
@ -19,23 +20,24 @@ import 'package:immich_mobile/providers/user.provider.dart';
import 'package:immich_mobile/widgets/common/immich_toast.dart'; import 'package:immich_mobile/widgets/common/immich_toast.dart';
class GalleryAppBar extends ConsumerWidget { class GalleryAppBar extends ConsumerWidget {
final Asset asset;
final void Function() showInfo; final void Function() showInfo;
final void Function() onToggleMotionVideo; final ValueNotifier<bool> isPlayingMotionVideo;
final bool isPlayingVideo;
const GalleryAppBar({ const GalleryAppBar({
super.key, super.key,
required this.asset,
required this.showInfo, required this.showInfo,
required this.onToggleMotionVideo, required this.isPlayingMotionVideo,
required this.isPlayingVideo,
}); });
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
final asset = ref.watch(currentAssetProvider);
if (asset == null) {
return const SizedBox();
}
final album = ref.watch(currentAlbumProvider); final album = ref.watch(currentAlbumProvider);
final isOwner = asset.ownerId == ref.watch(currentUserProvider)?.isarId; final isOwner = asset.ownerId == ref.watch(currentUserProvider)?.isarId;
final showControls = ref.watch(showControlsProvider);
final isPartner = ref final isPartner = ref
.watch(partnerSharedWithProvider) .watch(partnerSharedWithProvider)
@ -98,23 +100,24 @@ class GalleryAppBar extends ConsumerWidget {
} }
return IgnorePointer( return IgnorePointer(
ignoring: !ref.watch(showControlsProvider), ignoring: !showControls,
child: AnimatedOpacity( child: AnimatedOpacity(
duration: const Duration(milliseconds: 100), duration: const Duration(milliseconds: 100),
opacity: ref.watch(showControlsProvider) ? 1.0 : 0.0, opacity: showControls ? 1.0 : 0.0,
child: Container( child: Container(
color: Colors.black.withOpacity(0.4), color: Colors.black.withOpacity(0.4),
child: TopControlAppBar( child: TopControlAppBar(
isOwner: isOwner, isOwner: isOwner,
isPartner: isPartner, isPartner: isPartner,
isPlayingMotionVideo: isPlayingVideo, isPlayingMotionVideo: isPlayingMotionVideo.value,
asset: asset, asset: asset,
onMoreInfoPressed: showInfo, onMoreInfoPressed: showInfo,
onFavorite: toggleFavorite, onFavorite: toggleFavorite,
onRestorePressed: () => handleRestore(asset), onRestorePressed: () => handleRestore(asset),
onUploadPressed: asset.isLocal ? () => handleUpload(asset) : null, onUploadPressed: asset.isLocal ? () => handleUpload(asset) : null,
onDownloadPressed: asset.isLocal ? null : handleDownloadAsset, onDownloadPressed: asset.isLocal ? null : handleDownloadAsset,
onToggleMotionVideo: onToggleMotionVideo, onToggleMotionVideo: () =>
isPlayingMotionVideo.value = !isPlayingMotionVideo.value,
onAddToAlbumPressed: () => addToAlbum(asset), onAddToAlbumPressed: () => addToAlbum(asset),
onActivitiesPressed: handleActivities, onActivitiesPressed: handleActivities,
), ),