diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 856e74de4..d45ac6fe4 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -83,6 +83,11 @@ jobs: run: git apply $GITHUB_WORKSPACE/lib/scripts/bottom_sheet_patch.diff continue-on-error: true + - name: apply modal barrier patch + working-directory: ${{ env.FLUTTER_ROOT }} + run: git apply $GITHUB_WORKSPACE/lib/scripts/modal-barrier-patch.diff + continue-on-error: true + - name: Write key if: github.event_name == 'workflow_dispatch' run: | diff --git a/.github/workflows/ios.yml b/.github/workflows/ios.yml index dca79403c..915f9c5f0 100644 --- a/.github/workflows/ios.yml +++ b/.github/workflows/ios.yml @@ -30,6 +30,11 @@ jobs: shell: pwsh run: lib/scripts/build.ps1 + - name: apply modal barrier patch + working-directory: ${{ env.FLUTTER_ROOT }} + run: git apply $GITHUB_WORKSPACE/lib/scripts/modal-barrier-patch.diff + continue-on-error: true + - name: Build iOS run: | flutter build ios --release --no-codesign --dart-define-from-file=pili_release.json diff --git a/.github/workflows/linux_x64.yml b/.github/workflows/linux_x64.yml index a12b4b90d..2964dfca5 100644 --- a/.github/workflows/linux_x64.yml +++ b/.github/workflows/linux_x64.yml @@ -51,6 +51,11 @@ jobs: shell: pwsh run: lib/scripts/build.ps1 + - name: apply modal barrier patch + working-directory: ${{ env.FLUTTER_ROOT }} + run: git apply $GITHUB_WORKSPACE/lib/scripts/modal-barrier-patch.diff + continue-on-error: true + #TODO: deb and rpm packages need to be build - name: Build Linux run: flutter build linux --release -v --pub --dart-define-from-file=pili_release.json diff --git a/.github/workflows/mac.yml b/.github/workflows/mac.yml index 624adfd05..0c3a48deb 100644 --- a/.github/workflows/mac.yml +++ b/.github/workflows/mac.yml @@ -30,6 +30,11 @@ jobs: shell: pwsh run: lib/scripts/build.ps1 + - name: apply modal barrier patch + working-directory: ${{ env.FLUTTER_ROOT }} + run: git apply $GITHUB_WORKSPACE/lib/scripts/modal-barrier-patch.diff + continue-on-error: true + - name: Build Mac run: flutter build macos --release --dart-define-from-file=pili_release.json diff --git a/.github/workflows/win_x64.yml b/.github/workflows/win_x64.yml index a91c96cbc..c3cb9cd34 100644 --- a/.github/workflows/win_x64.yml +++ b/.github/workflows/win_x64.yml @@ -26,6 +26,12 @@ jobs: channel: stable flutter-version-file: pubspec.yaml + - name: apply modal barrier patch + working-directory: ${{ env.FLUTTER_ROOT }} + run: git apply $env:GITHUB_WORKSPACE\lib\scripts\modal-barrier-patch.diff + shell: pwsh + continue-on-error: true + - name: Add fastforge and Inno Setup run: | dart pub global activate fastforge diff --git a/lib/scripts/modal-barrier-patch.diff b/lib/scripts/modal-barrier-patch.diff new file mode 100644 index 000000000..53376856e --- /dev/null +++ b/lib/scripts/modal-barrier-patch.diff @@ -0,0 +1,192 @@ +diff --git a/packages/flutter/lib/src/material/popup_menu.dart b/packages/flutter/lib/src/material/popup_menu.dart +index 03a0ee2b8de..984e6ced68e 100644 +--- a/packages/flutter/lib/src/material/popup_menu.dart ++++ b/packages/flutter/lib/src/material/popup_menu.dart +@@ -1014,6 +1014,9 @@ class _PopupMenuRoute extends PopupRoute { + @override + final String barrierLabel; + ++ @override ++ bool get isMenu => true; ++ + @override + Widget buildPage( + BuildContext context, +diff --git a/packages/flutter/lib/src/widgets/modal_barrier.dart b/packages/flutter/lib/src/widgets/modal_barrier.dart +index 7b83d9c42cb..3946aa4950a 100644 +--- a/packages/flutter/lib/src/widgets/modal_barrier.dart ++++ b/packages/flutter/lib/src/widgets/modal_barrier.dart +@@ -131,6 +131,7 @@ class ModalBarrier extends StatelessWidget { + super.key, + this.color, + this.dismissible = true, ++ this.isMenu = false, + this.onDismiss, + this.semanticsLabel, + this.barrierSemanticsDismissible = true, +@@ -159,6 +160,8 @@ class ModalBarrier extends StatelessWidget { + /// [ModalBarrier] built by [ModalRoute] pages. + final bool dismissible; + ++ final bool isMenu; ++ + /// {@template flutter.widgets.ModalBarrier.onDismiss} + /// Called when the barrier is being dismissed. + /// +@@ -264,7 +267,11 @@ class ModalBarrier extends StatelessWidget { + return BlockSemantics( + child: ExcludeSemantics( + excluding: excluding, +- child: _ModalBarrierGestureDetector(onDismiss: handleDismiss, child: barrier), ++ child: _ModalBarrierGestureDetector( ++ onAnyTapUp: isMenu ? null : handleDismiss, ++ onAnyTapDown: isMenu ? handleDismiss : null, ++ child: barrier, ++ ), + ), + ); + } +@@ -292,6 +299,7 @@ class AnimatedModalBarrier extends AnimatedWidget { + super.key, + required Animation color, + this.dismissible = true, ++ this.isMenu = false, + this.semanticsLabel, + this.barrierSemanticsDismissible, + this.onDismiss, +@@ -315,6 +323,8 @@ class AnimatedModalBarrier extends AnimatedWidget { + /// [AnimatedModalBarrier] built by [ModalRoute] pages. + final bool dismissible; + ++ final bool isMenu; ++ + /// Semantics label used for the barrier if it is [dismissible]. + /// + /// The semantics label is read out by accessibility tools (e.g. TalkBack +@@ -359,6 +369,7 @@ class AnimatedModalBarrier extends AnimatedWidget { + onDismiss: onDismiss, + clipDetailsNotifier: clipDetailsNotifier, + semanticsOnTapHint: semanticsOnTapHint, ++ isMenu: isMenu, + ); + } + } +@@ -372,10 +383,12 @@ class _AnyTapGestureRecognizer extends BaseTapGestureRecognizer { + + VoidCallback? onAnyTapUp; + ++ VoidCallback? onAnyTapDown; ++ + @protected + @override + bool isPointerAllowed(PointerDownEvent event) { +- if (onAnyTapUp == null) { ++ if (onAnyTapUp == null && onAnyTapDown == null) { + return false; + } + return super.isPointerAllowed(event); +@@ -384,7 +397,9 @@ class _AnyTapGestureRecognizer extends BaseTapGestureRecognizer { + @protected + @override + void handleTapDown({PointerDownEvent? down}) { +- // Do nothing. ++ if (onAnyTapDown != null) { ++ invokeCallback('onAnyTapDown', onAnyTapDown!); ++ } + } + + @protected +@@ -401,28 +416,41 @@ class _AnyTapGestureRecognizer extends BaseTapGestureRecognizer { + // Do nothing. + } + ++ // @override ++ // void handleEvent(PointerEvent event) { ++ // assert(state != GestureRecognizerState.ready); ++ // if (state == GestureRecognizerState.possible && event.pointer == primaryPointer) { ++ // handlePrimaryPointer(event); ++ // } ++ // stopTrackingIfPointerNoLongerDown(event); ++ // } ++ + @override + String get debugDescription => 'any tap'; + } + + class _AnyTapGestureRecognizerFactory extends GestureRecognizerFactory<_AnyTapGestureRecognizer> { +- const _AnyTapGestureRecognizerFactory({this.onAnyTapUp}); ++ const _AnyTapGestureRecognizerFactory({this.onAnyTapUp, this.onAnyTapDown}); + + final VoidCallback? onAnyTapUp; + ++ final VoidCallback? onAnyTapDown; ++ + @override + _AnyTapGestureRecognizer constructor() => _AnyTapGestureRecognizer(); + + @override + void initializer(_AnyTapGestureRecognizer instance) { +- instance.onAnyTapUp = onAnyTapUp; ++ instance ++ ..onAnyTapUp = onAnyTapUp ++ ..onAnyTapDown = onAnyTapDown; + } + } + + // A GestureDetector used by ModalBarrier. It only has one callback, + // [onAnyTapDown], which recognizes tap down unconditionally. + class _ModalBarrierGestureDetector extends StatelessWidget { +- const _ModalBarrierGestureDetector({required this.child, required this.onDismiss}); ++ const _ModalBarrierGestureDetector({required this.child, this.onAnyTapUp, this.onAnyTapDown}); + + /// The widget below this widget in the tree. + /// See [RawGestureDetector.child]. +@@ -430,12 +458,17 @@ class _ModalBarrierGestureDetector extends StatelessWidget { + + /// Immediately called when an event that should dismiss the modal barrier + /// has happened. +- final VoidCallback onDismiss; ++ final VoidCallback? onAnyTapUp; ++ ++ final VoidCallback? onAnyTapDown; + + @override + Widget build(BuildContext context) { + final Map gestures = { +- _AnyTapGestureRecognizer: _AnyTapGestureRecognizerFactory(onAnyTapUp: onDismiss), ++ _AnyTapGestureRecognizer: _AnyTapGestureRecognizerFactory( ++ onAnyTapUp: onAnyTapUp, ++ onAnyTapDown: onAnyTapDown, ++ ), + }; + + return RawGestureDetector(gestures: gestures, behavior: HitTestBehavior.opaque, child: child); +diff --git a/packages/flutter/lib/src/widgets/routes.dart b/packages/flutter/lib/src/widgets/routes.dart +index 48927ea4ba5..25e9848b381 100644 +--- a/packages/flutter/lib/src/widgets/routes.dart ++++ b/packages/flutter/lib/src/widgets/routes.dart +@@ -1715,6 +1715,8 @@ abstract class ModalRoute extends TransitionRoute with LocalHistoryRoute false; ++ + /// Whether the semantics of the modal barrier are included in the + /// semantics tree. + /// +@@ -2291,6 +2293,7 @@ abstract class ModalRoute extends TransitionRoute with LocalHistoryRoute extends TransitionRoute with LocalHistoryRoute