[mob][photos] Swipe lock for multiple files (#2631)

This commit is contained in:
Ashil
2024-08-09 12:13:51 +05:30
committed by GitHub
10 changed files with 108 additions and 81 deletions

View File

@@ -1,7 +0,0 @@
import "package:photos/events/event.dart";
class FileSwipeLockEvent extends Event {
final bool shouldSwipeLock;
FileSwipeLockEvent(this.shouldSwipeLock);
}

View File

@@ -0,0 +1,7 @@
import "package:photos/events/event.dart";
class GuestViewEvent extends Event {
final bool isGuestView;
final bool swipeLocked;
GuestViewEvent(this.isGuestView, this.swipeLocked);
}

View File

@@ -8,6 +8,7 @@ import "package:logging/logging.dart";
import "package:modal_bottom_sheet/modal_bottom_sheet.dart";
import 'package:photos/core/configuration.dart';
import "package:photos/core/event_bus.dart";
import "package:photos/events/guest_view_event.dart";
import "package:photos/events/people_changed_event.dart";
import "package:photos/face/model/person.dart";
import "package:photos/generated/l10n.dart";
@@ -32,9 +33,9 @@ import 'package:photos/ui/components/action_sheet_widget.dart';
import "package:photos/ui/components/bottom_action_bar/selection_action_button_widget.dart";
import 'package:photos/ui/components/buttons/button_widget.dart';
import 'package:photos/ui/components/models/button_type.dart';
// import 'package:photos/ui/sharing/manage_links_widget.dart';
import "package:photos/ui/sharing/show_images_prevew.dart";
import "package:photos/ui/tools/collage/collage_creator_page.dart";
import "package:photos/ui/viewer/file/detail_page.dart";
import "package:photos/ui/viewer/location/update_location_data_widget.dart";
import 'package:photos/utils/delete_file_util.dart';
import "package:photos/utils/dialog_util.dart";
@@ -271,7 +272,13 @@ class _FileSelectionActionsWidgetState
),
);
}
items.add(
SelectionActionButton(
icon: Icons.lock,
labelText: "Guest view",
onTap: _onGuestViewClick,
),
);
items.add(
SelectionActionButton(
icon: Icons.grid_view_outlined,
@@ -559,6 +566,23 @@ class _FileSelectionActionsWidgetState
}
}
Future<void> _onGuestViewClick() async {
final List<EnteFile> selectedFiles = widget.selectedFiles.files.toList();
final page = DetailPage(
DetailPageConfiguration(
selectedFiles,
null,
0,
"guest_view",
),
);
routeToPage(context, page, forceCustomPageRoute: true).ignore();
WidgetsBinding.instance.addPostFrameCallback((_) {
Bus.instance.fire(GuestViewEvent(true, false));
});
widget.selectedFiles.clearAll();
}
Future<void> _onArchiveClick() async {
await changeVisibility(
context,

View File

@@ -10,7 +10,7 @@ import 'package:photos/core/configuration.dart';
import 'package:photos/core/constants.dart';
import 'package:photos/core/errors.dart';
import "package:photos/core/event_bus.dart";
import "package:photos/events/file_swipe_lock_event.dart";
import "package:photos/events/guest_view_event.dart";
import "package:photos/generated/l10n.dart";
import 'package:photos/models/file/file.dart';
import "package:photos/models/file/file_type.dart";
@@ -86,9 +86,9 @@ class _DetailPageState extends State<DetailPage> {
bool _hasLoadedTillEnd = false;
final _enableFullScreenNotifier = ValueNotifier(false);
bool _isFirstOpened = true;
bool isFileSwipeLocked = false;
late final StreamSubscription<FileSwipeLockEvent>
_fileSwipeLockEventSubscription;
bool isGuestView = false;
bool swipeLocked = false;
late final StreamSubscription<GuestViewEvent> _guestViewEventSubscription;
@override
void initState() {
@@ -99,17 +99,18 @@ class _DetailPageState extends State<DetailPage> {
_selectedIndexNotifier.value = widget.config.selectedIndex;
_preloadEntries();
_pageController = PageController(initialPage: _selectedIndexNotifier.value);
_fileSwipeLockEventSubscription =
Bus.instance.on<FileSwipeLockEvent>().listen((event) {
_guestViewEventSubscription =
Bus.instance.on<GuestViewEvent>().listen((event) {
setState(() {
isFileSwipeLocked = event.shouldSwipeLock;
isGuestView = event.isGuestView;
swipeLocked = event.swipeLocked;
});
});
}
@override
void dispose() {
_fileSwipeLockEventSubscription.cancel();
_guestViewEventSubscription.cancel();
_pageController.dispose();
_enableFullScreenNotifier.dispose();
_selectedIndexNotifier.dispose();
@@ -138,12 +139,12 @@ class _DetailPageState extends State<DetailPage> {
" files .",
);
return PopScope(
canPop: !isFileSwipeLocked,
canPop: !isGuestView,
onPopInvoked: (didPop) async {
if (isFileSwipeLocked) {
if (isGuestView) {
final authenticated = await _requestAuthentication();
if (authenticated) {
Bus.instance.fire(FileSwipeLockEvent(false));
Bus.instance.fire(GuestViewEvent(false, false));
}
}
},
@@ -176,7 +177,7 @@ class _DetailPageState extends State<DetailPage> {
_files![selectedIndex],
_onEditFileRequested,
widget.config.mode == DetailPageMode.minimalistic &&
!isFileSwipeLocked,
!isGuestView,
onFileRemoved: _onFileRemoved,
userID: Configuration.instance.getUserID(),
enableFullScreenNotifier: _enableFullScreenNotifier,
@@ -235,9 +236,10 @@ class _DetailPageState extends State<DetailPage> {
} else {
_selectedIndexNotifier.value = index;
}
Bus.instance.fire(GuestViewEvent(isGuestView, swipeLocked));
_preloadEntries();
},
physics: _shouldDisableScroll || isFileSwipeLocked
physics: _shouldDisableScroll || swipeLocked
? const NeverScrollableScrollPhysics()
: const FastScrollPhysics(speedFactor: 4.0),
controller: _pageController,

View File

@@ -6,7 +6,7 @@ import "package:local_auth/local_auth.dart";
import 'package:logging/logging.dart';
import 'package:media_extension/media_extension.dart';
import "package:photos/core/event_bus.dart";
import "package:photos/events/file_swipe_lock_event.dart";
import "package:photos/events/guest_view_event.dart";
import "package:photos/generated/l10n.dart";
import "package:photos/l10n/l10n.dart";
import "package:photos/models/file/extensions/file_props.dart";
@@ -51,9 +51,8 @@ class FileAppBar extends StatefulWidget {
class FileAppBarState extends State<FileAppBar> {
final _logger = Logger("FadingAppBar");
final List<Widget> _actions = [];
late final StreamSubscription<FileSwipeLockEvent>
_fileSwipeLockEventSubscription;
bool _isFileSwipeLocked = false;
late final StreamSubscription<GuestViewEvent> _guestViewEventSubscription;
bool isGuestView = false;
@override
void didUpdateWidget(FileAppBar oldWidget) {
@@ -66,17 +65,17 @@ class FileAppBarState extends State<FileAppBar> {
@override
void initState() {
super.initState();
_fileSwipeLockEventSubscription =
Bus.instance.on<FileSwipeLockEvent>().listen((event) {
_guestViewEventSubscription =
Bus.instance.on<GuestViewEvent>().listen((event) {
setState(() {
_isFileSwipeLocked = event.shouldSwipeLock;
isGuestView = event.isGuestView;
});
});
}
@override
void dispose() {
_fileSwipeLockEventSubscription.cancel();
_guestViewEventSubscription.cancel();
super.dispose();
}
@@ -124,19 +123,19 @@ class FileAppBarState extends State<FileAppBar> {
switchOutCurve: Curves.easeInOut,
child: AppBar(
clipBehavior: Clip.none,
key: ValueKey(_isFileSwipeLocked),
key: ValueKey(isGuestView),
iconTheme: const IconThemeData(
color: Colors.white,
), //same for both themes
leading: IconButton(
icon: const Icon(Icons.arrow_back),
onPressed: () {
_isFileSwipeLocked
isGuestView
? _requestAuthentication()
: Navigator.of(context).pop();
},
),
actions: shouldShowActions && !_isFileSwipeLocked ? _actions : [],
actions: shouldShowActions && !isGuestView ? _actions : [],
elevation: 0,
backgroundColor: const Color(0x00000000),
),
@@ -306,7 +305,7 @@ class FileAppBarState extends State<FileAppBar> {
const Padding(
padding: EdgeInsets.all(8),
),
const Text("Swipe lock"),
const Text("Guest view"),
],
),
),
@@ -329,7 +328,7 @@ class FileAppBarState extends State<FileAppBar> {
} else if (value == 5) {
await _handleUnHideRequest(context);
} else if (value == 6) {
await _onSwipeLock();
await _onTapGuestView();
}
},
),
@@ -413,9 +412,9 @@ class FileAppBarState extends State<FileAppBar> {
}
}
Future<void> _onSwipeLock() async {
Future<void> _onTapGuestView() async {
if (await LocalAuthentication().isDeviceSupported()) {
Bus.instance.fire(FileSwipeLockEvent(!_isFileSwipeLocked));
Bus.instance.fire(GuestViewEvent(true, true));
} else {
await showErrorDialog(
context,
@@ -432,7 +431,7 @@ class FileAppBarState extends State<FileAppBar> {
"Please authenticate to view more photos and videos.",
);
if (hasAuthenticated) {
Bus.instance.fire(FileSwipeLockEvent(false));
Bus.instance.fire(GuestViewEvent(false, false));
}
}
}

View File

@@ -5,7 +5,7 @@ import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import "package:logging/logging.dart";
import "package:photos/core/event_bus.dart";
import "package:photos/events/file_swipe_lock_event.dart";
import "package:photos/events/guest_view_event.dart";
import "package:photos/generated/l10n.dart";
import "package:photos/models/file/extensions/file_props.dart";
import 'package:photos/models/file/file.dart';
@@ -47,26 +47,25 @@ class FileBottomBar extends StatefulWidget {
class FileBottomBarState extends State<FileBottomBar> {
final GlobalKey shareButtonKey = GlobalKey();
bool _isFileSwipeLocked = false;
late final StreamSubscription<FileSwipeLockEvent>
_fileSwipeLockEventSubscription;
bool isGuestView = false;
late final StreamSubscription<GuestViewEvent> _guestViewEventSubscription;
bool isPanorama = false;
int? lastFileGenID;
@override
void initState() {
super.initState();
_fileSwipeLockEventSubscription =
Bus.instance.on<FileSwipeLockEvent>().listen((event) {
_guestViewEventSubscription =
Bus.instance.on<GuestViewEvent>().listen((event) {
setState(() {
_isFileSwipeLocked = event.shouldSwipeLock;
isGuestView = event.isGuestView;
});
});
}
@override
void dispose() {
_fileSwipeLockEventSubscription.cancel();
_guestViewEventSubscription.cancel();
super.dispose();
}
@@ -220,9 +219,9 @@ class FileBottomBarState extends State<FileBottomBar> {
valueListenable: widget.enableFullScreenNotifier,
builder: (BuildContext context, bool isFullScreen, _) {
return IgnorePointer(
ignoring: isFullScreen || _isFileSwipeLocked,
ignoring: isFullScreen || isGuestView,
child: AnimatedOpacity(
opacity: isFullScreen || _isFileSwipeLocked ? 0 : 1,
opacity: isFullScreen || isGuestView ? 0 : 1,
duration: const Duration(milliseconds: 250),
curve: Curves.easeInOut,
child: Align(

View File

@@ -7,7 +7,7 @@ import 'package:flutter/material.dart';
import 'package:logging/logging.dart';
import 'package:photos/core/constants.dart';
import "package:photos/core/event_bus.dart";
import "package:photos/events/file_swipe_lock_event.dart";
import "package:photos/events/guest_view_event.dart";
import "package:photos/generated/l10n.dart";
import "package:photos/models/file/extensions/file_props.dart";
import 'package:photos/models/file/file.dart';
@@ -48,9 +48,8 @@ class _VideoWidgetState extends State<VideoWidget> {
final _progressNotifier = ValueNotifier<double?>(null);
bool _isPlaying = false;
final EnteWakeLock _wakeLock = EnteWakeLock();
bool _isFileSwipeLocked = false;
late final StreamSubscription<FileSwipeLockEvent>
_fileSwipeLockEventSubscription;
bool isGuestView = false;
late final StreamSubscription<GuestViewEvent> _guestViewEventSubscription;
@override
void initState() {
@@ -80,10 +79,10 @@ class _VideoWidgetState extends State<VideoWidget> {
}
});
}
_fileSwipeLockEventSubscription =
Bus.instance.on<FileSwipeLockEvent>().listen((event) {
_guestViewEventSubscription =
Bus.instance.on<GuestViewEvent>().listen((event) {
setState(() {
_isFileSwipeLocked = event.shouldSwipeLock;
isGuestView = event.isGuestView;
});
});
}
@@ -132,7 +131,7 @@ class _VideoWidgetState extends State<VideoWidget> {
@override
void dispose() {
_fileSwipeLockEventSubscription.cancel();
_guestViewEventSubscription.cancel();
removeCallBack(widget.file);
_videoPlayerController?.dispose();
_chewieController?.dispose();
@@ -188,7 +187,7 @@ class _VideoWidgetState extends State<VideoWidget> {
? _getVideoPlayer()
: _getLoadingWidget();
final contentWithDetector = GestureDetector(
onVerticalDragUpdate: _isFileSwipeLocked
onVerticalDragUpdate: isGuestView
? null
: (d) => {
if (d.delta.dy > dragSensitivity)

View File

@@ -8,7 +8,7 @@ import "package:media_kit/media_kit.dart";
import "package:media_kit_video/media_kit_video.dart";
import "package:photos/core/constants.dart";
import "package:photos/core/event_bus.dart";
import "package:photos/events/file_swipe_lock_event.dart";
import "package:photos/events/guest_view_event.dart";
import "package:photos/events/pause_video_event.dart";
import "package:photos/generated/l10n.dart";
import "package:photos/models/file/extensions/file_props.dart";
@@ -47,9 +47,8 @@ class _VideoWidgetNewState extends State<VideoWidgetNew>
late StreamSubscription<bool> playingStreamSubscription;
bool _isAppInFG = true;
late StreamSubscription<PauseVideoEvent> pauseVideoSubscription;
bool _isFileSwipeLocked = false;
late final StreamSubscription<FileSwipeLockEvent>
_fileSwipeLockEventSubscription;
bool isGuestView = false;
late final StreamSubscription<GuestViewEvent> _guestViewEventSubscription;
@override
void initState() {
@@ -94,10 +93,10 @@ class _VideoWidgetNewState extends State<VideoWidgetNew>
pauseVideoSubscription = Bus.instance.on<PauseVideoEvent>().listen((event) {
player.pause();
});
_fileSwipeLockEventSubscription =
Bus.instance.on<FileSwipeLockEvent>().listen((event) {
_guestViewEventSubscription =
Bus.instance.on<GuestViewEvent>().listen((event) {
setState(() {
_isFileSwipeLocked = event.shouldSwipeLock;
isGuestView = event.isGuestView;
});
});
}
@@ -113,7 +112,7 @@ class _VideoWidgetNewState extends State<VideoWidgetNew>
@override
void dispose() {
_fileSwipeLockEventSubscription.cancel();
_guestViewEventSubscription.cancel();
pauseVideoSubscription.cancel();
removeCallBack(widget.file);
_progressNotifier.dispose();
@@ -159,7 +158,7 @@ class _VideoWidgetNewState extends State<VideoWidgetNew>
),
fullscreen: const MaterialVideoControlsThemeData(),
child: GestureDetector(
onVerticalDragUpdate: _isFileSwipeLocked
onVerticalDragUpdate: isGuestView
? null
: (d) => {
if (d.delta.dy > dragSensitivity)

View File

@@ -9,8 +9,7 @@ import 'package:photos/core/cache/thumbnail_in_memory_cache.dart';
import 'package:photos/core/constants.dart';
import 'package:photos/core/event_bus.dart';
import 'package:photos/db/files_db.dart';
import "package:photos/events/file_swipe_lock_event.dart";
import 'package:photos/events/files_updated_event.dart';
import "package:photos/events/files_updated_event.dart";
import 'package:photos/events/local_photos_updated_event.dart';
import "package:photos/models/file/extensions/file_props.dart";
import 'package:photos/models/file/file.dart';
@@ -26,6 +25,7 @@ class ZoomableImage extends StatefulWidget {
final String? tagPrefix;
final Decoration? backgroundDecoration;
final bool shouldCover;
final bool isGuestView;
const ZoomableImage(
this.photo, {
@@ -34,6 +34,7 @@ class ZoomableImage extends StatefulWidget {
required this.tagPrefix,
this.backgroundDecoration,
this.shouldCover = false,
this.isGuestView = false,
});
@override
@@ -54,9 +55,6 @@ class _ZoomableImageState extends State<ZoomableImage> {
bool _isZooming = false;
PhotoViewController _photoViewController = PhotoViewController();
final _scaleStateController = PhotoViewScaleStateController();
bool _isFileSwipeLocked = false;
late final StreamSubscription<FileSwipeLockEvent>
_fileSwipeLockEventSubscription;
@override
void initState() {
@@ -72,17 +70,10 @@ class _ZoomableImageState extends State<ZoomableImage> {
debugPrint("isZooming = $_isZooming, currentState $value");
// _logger.info('is reakky zooming $_isZooming with state $value');
};
_fileSwipeLockEventSubscription =
Bus.instance.on<FileSwipeLockEvent>().listen((event) {
setState(() {
_isFileSwipeLocked = event.shouldSwipeLock;
});
});
}
@override
void dispose() {
_fileSwipeLockEventSubscription.cancel();
_photoViewController.dispose();
_scaleStateController.dispose();
super.dispose();
@@ -159,7 +150,7 @@ class _ZoomableImageState extends State<ZoomableImage> {
}
final GestureDragUpdateCallback? verticalDragCallback =
_isZooming || _isFileSwipeLocked
_isZooming || widget.isGuestView
? null
: (d) => {
if (!_isZooming)

View File

@@ -1,3 +1,4 @@
import "dart:async";
import "dart:io";
import 'package:flutter/material.dart';
@@ -5,6 +6,8 @@ import 'package:logging/logging.dart';
import "package:media_kit/media_kit.dart";
import "package:media_kit_video/media_kit_video.dart";
import 'package:motion_photos/motion_photos.dart';
import "package:photos/core/event_bus.dart";
import "package:photos/events/guest_view_event.dart";
import "package:photos/generated/l10n.dart";
import "package:photos/models/file/extensions/file_props.dart";
import 'package:photos/models/file/file.dart';
@@ -23,11 +26,11 @@ class ZoomableLiveImageNew extends StatefulWidget {
const ZoomableLiveImageNew(
this.enteFile, {
Key? key,
super.key,
this.shouldDisableScroll,
required this.tagPrefix,
this.backgroundDecoration,
}) : super(key: key);
});
@override
State<ZoomableLiveImageNew> createState() => _ZoomableLiveImageNewState();
@@ -43,6 +46,9 @@ class _ZoomableLiveImageNewState extends State<ZoomableLiveImageNew>
late final _player = Player();
VideoController? _videoController;
bool isGuestView = false;
late final StreamSubscription<GuestViewEvent> _guestViewEventSubscription;
@override
void initState() {
_enteFile = widget.enteFile;
@@ -52,6 +58,12 @@ class _ZoomableLiveImageNewState extends State<ZoomableLiveImageNew>
if (_enteFile.isLivePhoto && _enteFile.isUploaded) {
LocalFileUpdateService.instance.checkLivePhoto(_enteFile).ignore();
}
_guestViewEventSubscription =
Bus.instance.on<GuestViewEvent>().listen((event) {
setState(() {
isGuestView = event.isGuestView;
});
});
super.initState();
}
@@ -83,6 +95,7 @@ class _ZoomableLiveImageNewState extends State<ZoomableLiveImageNew>
tagPrefix: widget.tagPrefix,
shouldDisableScroll: widget.shouldDisableScroll,
backgroundDecoration: widget.backgroundDecoration,
isGuestView: isGuestView,
);
}
return GestureDetector(
@@ -98,6 +111,7 @@ class _ZoomableLiveImageNewState extends State<ZoomableLiveImageNew>
_videoController!.player.stop();
_videoController!.player.dispose();
}
_guestViewEventSubscription.cancel();
super.dispose();
}