1
0
Fork 0
mirror of https://github.com/immich-app/immich.git synced 2024-12-29 15:11:58 +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
bool get isImage => type == AssetType.image;
@ignore
bool get isVideo => type == AssetType.video;
@ignore
bool get isMotionPhoto => livePhotoVideoId != null;

View file

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

View file

@ -184,8 +184,8 @@ class NativeVideoViewerPage extends HookConsumerWidget {
try {
if (mute && playbackInfo.volume != 0.0) {
await playerController.setVolume(0.0);
} else if (!mute && playbackInfo.volume != 0.7) {
await playerController.setVolume(0.7);
} else if (!mute && playbackInfo.volume != 0.9) {
await playerController.setVolume(0.9);
}
} catch (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/current_album.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/show_controls.provider.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';
class BottomGalleryBar extends ConsumerWidget {
final Asset asset;
final ValueNotifier<int> assetIndex;
final bool showStack;
final int stackIndex;
final ValueNotifier<int> totalAssets;
final bool showVideoPlayerControls;
final PageController controller;
final RenderList renderList;
@ -39,17 +38,20 @@ class BottomGalleryBar extends ConsumerWidget {
super.key,
required this.showStack,
required this.stackIndex,
required this.asset,
required this.assetIndex,
required this.controller,
required this.totalAssets,
required this.showVideoPlayerControls,
required this.renderList,
});
@override
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 showControls = ref.watch(showControlsProvider);
final stackItems = showStack && asset.stackCount > 0
? ref.watch(assetStackStateProvider(asset))
@ -324,7 +326,7 @@ class BottomGalleryBar extends ConsumerWidget {
},
];
return IgnorePointer(
ignoring: !ref.watch(showControlsProvider),
ignoring: !showControls,
child: AnimatedOpacity(
duration: const Duration(milliseconds: 100),
opacity: ref.watch(showControlsProvider) ? 1.0 : 0.0,
@ -341,7 +343,7 @@ class BottomGalleryBar extends ConsumerWidget {
padding: EdgeInsets.only(top: 40.0),
child: Column(
children: [
if (showVideoPlayerControls) const VideoControls(),
if (asset.isVideo) const VideoControls(),
BottomNavigationBar(
elevation: 0.0,
backgroundColor: Colors.transparent,

View file

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

View file

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