diff --git a/mobile/lib/states/pointer_position_provider.dart b/mobile/lib/states/pointer_position_provider.dart deleted file mode 100644 index 3254f476c0..0000000000 --- a/mobile/lib/states/pointer_position_provider.dart +++ /dev/null @@ -1,68 +0,0 @@ -import "dart:async"; - -import "package:flutter/widgets.dart"; - -class PointerPositionProvider extends StatefulWidget { - final Widget child; - const PointerPositionProvider({ - super.key, - required this.child, - }); - - @override - State createState() => - _PointerPositionProviderState(); -} - -class _PointerPositionProviderState extends State { - @override - void dispose() { - PointerPosition.of(context).pointerPositionStreamController.close(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return PointerPosition( - child: Builder( - builder: (context) { - return Listener( - onPointerMove: (PointerMoveEvent event) { - PointerPosition.of(context) - .pointerPositionStreamController - .add(event.localPosition); - }, - child: widget.child, - ); - }, - ), - ); - } -} - -class PointerPosition extends InheritedWidget { - PointerPosition({super.key, required super.child}); - - final StreamController pointerPositionStreamController = - StreamController.broadcast(); - - Future closeController() { - debugPrint("dragToSelect: Closing stream controller"); - return pointerPositionStreamController.close(); - } - - static PointerPosition? maybeOf(BuildContext context) { - return context.dependOnInheritedWidgetOfExactType(); - } - - static PointerPosition of(BuildContext context) { - final PointerPosition? result = maybeOf(context); - assert(result != null, 'No PointerPositionProvider found in context'); - return result!; - } - - @override - bool updateShouldNotify(PointerPosition oldWidget) => - pointerPositionStreamController != - oldWidget.pointerPositionStreamController; -} diff --git a/mobile/lib/states/pointer_provider.dart b/mobile/lib/states/pointer_provider.dart new file mode 100644 index 0000000000..d912fb3551 --- /dev/null +++ b/mobile/lib/states/pointer_provider.dart @@ -0,0 +1,98 @@ +import "dart:async"; + +import "package:flutter/widgets.dart"; + +class PointerProvider extends StatefulWidget { + final Widget child; + const PointerProvider({ + super.key, + required this.child, + }); + + @override + State createState() => _PointerProviderState(); +} + +class _PointerProviderState extends State { + @override + void dispose() { + Pointer.of(context).closePositionController(); + Pointer.of(context).closeDownEventController(); + Pointer.of(context).upDownEventController(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Pointer( + child: Builder( + builder: (context) { + return Listener( + onPointerMove: (event) { + if (event.delta.distance > 0) { + Pointer.of(context) + .positionStreamController + .add(event.localPosition); + } + }, + onPointerDown: (event) { + Pointer.of(context) + .downEventStreamController + .add(event.localPosition); + }, + onPointerUp: (event) { + Pointer.of(context) + .upEventStreamController + .add(event.localPosition); + }, + child: widget.child, + ); + }, + ), + ); + } +} + +class Pointer extends InheritedWidget { + Pointer({super.key, required super.child}); + + final StreamController positionStreamController = + StreamController.broadcast(); + + final StreamController downEventStreamController = + StreamController.broadcast(); + + final StreamController upEventStreamController = + StreamController.broadcast(); + + Future closePositionController() { + debugPrint("dragToSelect: Closing position stream controller"); + return positionStreamController.close(); + } + + Future closeDownEventController() { + debugPrint("dragToSelect: Closing down event stream controller"); + return downEventStreamController.close(); + } + + Future upDownEventController() { + debugPrint("dragToSelect: Closing up event stream controller"); + return upEventStreamController.close(); + } + + static Pointer? maybeOf(BuildContext context) { + return context.dependOnInheritedWidgetOfExactType(); + } + + static Pointer of(BuildContext context) { + final Pointer? result = maybeOf(context); + assert(result != null, 'No PointerPositionProvider found in context'); + return result!; + } + + @override + bool updateShouldNotify(Pointer oldWidget) => + positionStreamController != oldWidget.positionStreamController || + downEventStreamController != oldWidget.downEventStreamController || + upEventStreamController != oldWidget.upEventStreamController; +} diff --git a/mobile/lib/ui/viewer/gallery/component/gallery_file_widget.dart b/mobile/lib/ui/viewer/gallery/component/gallery_file_widget.dart index 0535b363c6..f2680d65ca 100644 --- a/mobile/lib/ui/viewer/gallery/component/gallery_file_widget.dart +++ b/mobile/lib/ui/viewer/gallery/component/gallery_file_widget.dart @@ -9,7 +9,7 @@ import "package:photos/core/constants.dart"; import 'package:photos/models/file/file.dart'; import "package:photos/models/selected_files.dart"; import "package:photos/services/app_lifecycle_service.dart"; -import "package:photos/states/pointer_position_provider.dart"; +import "package:photos/states/pointer_provider.dart"; import "package:photos/theme/ente_theme.dart"; import "package:photos/ui/viewer/file/detail_page.dart"; import "package:photos/ui/viewer/file/thumbnail_widget.dart"; @@ -46,9 +46,11 @@ class GalleryFileWidget extends StatefulWidget { class _GalleryFileWidgetState extends State { final _globalKey = GlobalKey(); - bool _insideBbox = false; + bool _pointerInsideBbox = false; bool _insideBboxPrevValue = false; late StreamSubscription _pointerPositionStreamSubscription; + late StreamSubscription _pointerDownEventStreamSubscription; + late StreamSubscription _pointerUpEventStreamSubscription; final _logger = Logger("GalleryFileWidget"); @override @@ -76,24 +78,42 @@ class _GalleryFileWidgetState extends State { size.width, size.height, ); - _pointerPositionStreamSubscription = PointerPosition.of(context) - .pointerPositionStreamController + + _pointerUpEventStreamSubscription = Pointer.of(context) + .upEventStreamController + .stream + .listen((event) { + if (bbox.contains(event)) { + if (_pointerInsideBbox) _pointerInsideBbox = false; + } + }); + + _pointerDownEventStreamSubscription = Pointer.of(context) + .downEventStreamController + .stream + .listen((event) { + if (bbox.contains(event)) { + // widget.selectedFiles!.toggleSelection(widget.file); + // _insideBbox = true; + } + }); + + _pointerPositionStreamSubscription = Pointer.of(context) + .positionStreamController .stream .listen((event) { if (widget.selectedFiles?.files.isEmpty ?? true) return; - _insideBboxPrevValue = _insideBbox; + _insideBboxPrevValue = _pointerInsideBbox; if (bbox.contains(event)) { - _insideBbox = true; + _pointerInsideBbox = true; } else { - _insideBbox = false; + _pointerInsideBbox = false; } - if (_insideBbox == true && _insideBboxPrevValue == false) { + if (_pointerInsideBbox == true && _insideBboxPrevValue == false) { // print('Entered ${widget.file.displayName}'); widget.selectedFiles!.toggleSelection(widget.file); - } else if (_insideBbox == false && _insideBboxPrevValue == true) { - // print('Exited ${widget.index}'); } }); } catch (e) { @@ -107,6 +127,8 @@ class _GalleryFileWidgetState extends State { @override void dispose() { _pointerPositionStreamSubscription.cancel(); + _pointerDownEventStreamSubscription.cancel(); + _pointerUpEventStreamSubscription.cancel(); super.dispose(); } @@ -210,6 +232,7 @@ class _GalleryFileWidgetState extends State { GalleryContextState.of(context)!.inSelectionMode; if (shouldToggleSelection) { _toggleFileSelection(file); + _pointerInsideBbox = true; } else { if (AppLifecycleService.instance.mediaExtensionAction.action == IntentAction.pick) { @@ -228,6 +251,7 @@ class _GalleryFileWidgetState extends State { IntentAction.main) { HapticFeedback.lightImpact(); _toggleFileSelection(file); + _pointerInsideBbox = true; } } diff --git a/mobile/lib/ui/viewer/gallery/component/group/lazy_group_gallery.dart b/mobile/lib/ui/viewer/gallery/component/group/lazy_group_gallery.dart index 6f58c195aa..f1567d960a 100644 --- a/mobile/lib/ui/viewer/gallery/component/group/lazy_group_gallery.dart +++ b/mobile/lib/ui/viewer/gallery/component/group/lazy_group_gallery.dart @@ -7,7 +7,7 @@ import 'package:photos/core/constants.dart'; import 'package:photos/events/files_updated_event.dart'; import 'package:photos/models/file/file.dart'; import 'package:photos/models/selected_files.dart'; -import "package:photos/states/pointer_position_provider.dart"; +import "package:photos/states/pointer_provider.dart"; import 'package:photos/theme/ente_theme.dart'; import "package:photos/ui/viewer/gallery/component/grid/place_holder_grid_view_widget.dart"; import "package:photos/ui/viewer/gallery/component/group/group_gallery.dart"; @@ -235,7 +235,7 @@ class _LazyGroupGalleryState extends State { ), ], ), - PointerPositionProvider( + PointerProvider( child: GroupGalleryGlobalKey( globalKey: _groupGalleryGlobalKey, child: SizedBox(