mirror of
https://github.com/venera-app/venera.git
synced 2025-12-15 06:41:14 +00:00
[iOS] Enable full screen swipe back gesture
This commit is contained in:
@@ -19,6 +19,7 @@ class AppPageRoute<T> extends PageRoute<T> with _AppRouteTransitionMixin{
|
||||
super.allowSnapshotting = true,
|
||||
super.barrierDismissible = false,
|
||||
this.enableIOSGesture = true,
|
||||
this.iosFullScreenPopGesture = true,
|
||||
this.preventRebuild = true,
|
||||
}) {
|
||||
assert(opaque);
|
||||
@@ -48,6 +49,9 @@ class AppPageRoute<T> extends PageRoute<T> with _AppRouteTransitionMixin{
|
||||
@override
|
||||
final bool enableIOSGesture;
|
||||
|
||||
@override
|
||||
final bool iosFullScreenPopGesture;
|
||||
|
||||
@override
|
||||
final bool preventRebuild;
|
||||
}
|
||||
@@ -74,6 +78,8 @@ mixin _AppRouteTransitionMixin<T> on PageRoute<T> {
|
||||
|
||||
bool get enableIOSGesture;
|
||||
|
||||
bool get iosFullScreenPopGesture;
|
||||
|
||||
bool get preventRebuild;
|
||||
|
||||
Widget? _child;
|
||||
@@ -121,20 +127,22 @@ mixin _AppRouteTransitionMixin<T> on PageRoute<T> {
|
||||
builder = PredictiveBackPageTransitionsBuilder();
|
||||
} else {
|
||||
builder = SlidePageTransitionBuilder();
|
||||
}
|
||||
}
|
||||
|
||||
return builder.buildTransitions(
|
||||
return builder.buildTransitions(
|
||||
this,
|
||||
context,
|
||||
animation,
|
||||
secondaryAnimation,
|
||||
enableIOSGesture && App.isIOS
|
||||
? IOSBackGestureDetector(
|
||||
gestureWidth: _kBackGestureWidth,
|
||||
enabledCallback: () => _isPopGestureEnabled<T>(this),
|
||||
onStartPopGesture: () => _startPopGesture(this),
|
||||
child: child)
|
||||
: child);
|
||||
enableIOSGesture && App.isIOS
|
||||
? IOSBackGestureDetector(
|
||||
gestureWidth: _kBackGestureWidth,
|
||||
enabledCallback: () => _isPopGestureEnabled<T>(this),
|
||||
onStartPopGesture: () => _startPopGesture(this),
|
||||
fullScreen: iosFullScreenPopGesture,
|
||||
child: child,
|
||||
)
|
||||
: child);
|
||||
}
|
||||
|
||||
IOSBackGestureController _startPopGesture(PageRoute<T> route) {
|
||||
@@ -206,6 +214,7 @@ class IOSBackGestureDetector extends StatefulWidget {
|
||||
required this.child,
|
||||
required this.gestureWidth,
|
||||
required this.onStartPopGesture,
|
||||
this.fullScreen = false,
|
||||
super.key});
|
||||
|
||||
final double gestureWidth;
|
||||
@@ -216,6 +225,8 @@ class IOSBackGestureDetector extends StatefulWidget {
|
||||
|
||||
final Widget child;
|
||||
|
||||
final bool fullScreen;
|
||||
|
||||
@override
|
||||
State<IOSBackGestureDetector> createState() => _IOSBackGestureDetectorState();
|
||||
}
|
||||
@@ -247,20 +258,30 @@ class _IOSBackGestureDetectorState extends State<IOSBackGestureDetector> {
|
||||
? MediaQuery.of(context).padding.left
|
||||
: MediaQuery.of(context).padding.right;
|
||||
dragAreaWidth = max(dragAreaWidth, widget.gestureWidth);
|
||||
final Widget gestureListener = widget.fullScreen
|
||||
? Positioned.fill(
|
||||
child: Listener(
|
||||
onPointerDown: _handlePointerDown,
|
||||
behavior: HitTestBehavior.translucent,
|
||||
),
|
||||
)
|
||||
: Positioned(
|
||||
width: dragAreaWidth,
|
||||
top: 0.0,
|
||||
bottom: 0.0,
|
||||
left: Directionality.of(context) == TextDirection.ltr ? 0.0 : null,
|
||||
right: Directionality.of(context) == TextDirection.rtl ? 0.0 : null,
|
||||
child: Listener(
|
||||
onPointerDown: _handlePointerDown,
|
||||
behavior: HitTestBehavior.translucent,
|
||||
),
|
||||
);
|
||||
|
||||
return Stack(
|
||||
fit: StackFit.passthrough,
|
||||
children: <Widget>[
|
||||
widget.child,
|
||||
Positioned(
|
||||
width: dragAreaWidth,
|
||||
top: 0.0,
|
||||
bottom: 0.0,
|
||||
left: 0,
|
||||
child: Listener(
|
||||
onPointerDown: _handlePointerDown,
|
||||
behavior: HitTestBehavior.translucent,
|
||||
),
|
||||
),
|
||||
gestureListener,
|
||||
],
|
||||
);
|
||||
}
|
||||
@@ -314,30 +335,31 @@ class SlidePageTransitionBuilder extends PageTransitionsBuilder {
|
||||
Animation<double> animation,
|
||||
Animation<double> secondaryAnimation,
|
||||
Widget child) {
|
||||
final Animation<double> primaryAnimation = App.isIOS
|
||||
? animation
|
||||
: CurvedAnimation(parent: animation, curve: Curves.ease);
|
||||
final Animation<double> secondaryCurve = App.isIOS
|
||||
? secondaryAnimation
|
||||
: CurvedAnimation(parent: secondaryAnimation, curve: Curves.ease);
|
||||
|
||||
return SlideTransition(
|
||||
position: Tween<Offset>(
|
||||
begin: const Offset(1, 0),
|
||||
end: Offset.zero,
|
||||
).animate(primaryAnimation),
|
||||
child: SlideTransition(
|
||||
position: Tween<Offset>(
|
||||
begin: const Offset(1, 0),
|
||||
end: Offset.zero,
|
||||
).animate(CurvedAnimation(
|
||||
parent: animation,
|
||||
curve: Curves.ease,
|
||||
)),
|
||||
child: SlideTransition(
|
||||
position: Tween<Offset>(
|
||||
begin: Offset.zero,
|
||||
end: const Offset(-0.4, 0),
|
||||
).animate(CurvedAnimation(
|
||||
parent: secondaryAnimation,
|
||||
curve: Curves.ease,
|
||||
)),
|
||||
child: PhysicalModel(
|
||||
color: Colors.transparent,
|
||||
borderRadius: BorderRadius.zero,
|
||||
clipBehavior: Clip.hardEdge,
|
||||
elevation: 6,
|
||||
child: Material(child: child,),
|
||||
),
|
||||
)
|
||||
begin: Offset.zero,
|
||||
end: const Offset(-0.4, 0),
|
||||
).animate(secondaryCurve),
|
||||
child: PhysicalModel(
|
||||
color: Colors.transparent,
|
||||
borderRadius: BorderRadius.zero,
|
||||
clipBehavior: Clip.hardEdge,
|
||||
elevation: 6,
|
||||
child: Material(child: child),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,14 +14,20 @@ extension Navigation on BuildContext {
|
||||
return Navigator.of(this).canPop();
|
||||
}
|
||||
|
||||
Future<T?> to<T>(Widget Function() builder) {
|
||||
return Navigator.of(this)
|
||||
.push<T>(AppPageRoute(builder: (context) => builder()));
|
||||
Future<T?> to<T>(Widget Function() builder,
|
||||
{bool enableIOSGesture = true, bool iosFullScreenGesture = true}) {
|
||||
return Navigator.of(this).push<T>(AppPageRoute(
|
||||
builder: (context) => builder(),
|
||||
enableIOSGesture: enableIOSGesture,
|
||||
iosFullScreenPopGesture: iosFullScreenGesture));
|
||||
}
|
||||
|
||||
Future<void> toReplacement<T>(Widget Function() builder) {
|
||||
return Navigator.of(this)
|
||||
.pushReplacement(AppPageRoute(builder: (context) => builder()));
|
||||
Future<void> toReplacement<T>(Widget Function() builder,
|
||||
{bool enableIOSGesture = true, bool iosFullScreenGesture = true}) {
|
||||
return Navigator.of(this).pushReplacement(AppPageRoute(
|
||||
builder: (context) => builder(),
|
||||
enableIOSGesture: enableIOSGesture,
|
||||
iosFullScreenPopGesture: iosFullScreenGesture));
|
||||
}
|
||||
|
||||
double get width => MediaQuery.of(this).size.width;
|
||||
|
||||
@@ -154,6 +154,8 @@ class LocalComic with HistoryMixin implements Comic {
|
||||
author: subtitle,
|
||||
tags: tags,
|
||||
),
|
||||
enableIOSGesture: false,
|
||||
iosFullScreenGesture: false,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -116,6 +116,8 @@ abstract mixin class _ComicPageActions {
|
||||
author: comic.findAuthor() ?? '',
|
||||
tags: comic.plainTags,
|
||||
),
|
||||
enableIOSGesture: false,
|
||||
iosFullScreenGesture: false,
|
||||
)
|
||||
.then((_) {
|
||||
onReadEnd();
|
||||
|
||||
@@ -236,7 +236,7 @@ class _ComicPageState extends LoadingState<ComicPage, ComicDetails>
|
||||
author: localComic.subTitle ?? '',
|
||||
tags: localComic.tags,
|
||||
);
|
||||
});
|
||||
}, enableIOSGesture: false, iosFullScreenGesture: false);
|
||||
App.mainNavigatorKey!.currentContext!.pop();
|
||||
});
|
||||
isFirst = false;
|
||||
|
||||
@@ -521,7 +521,9 @@ class _LocalFavoritesPageState extends State<_LocalFavoritesPage> {
|
||||
App.rootContext.to(() => ReaderWithLoading(
|
||||
id: c.id,
|
||||
sourceKey: c.sourceKey,
|
||||
));
|
||||
),
|
||||
enableIOSGesture: false,
|
||||
iosFullScreenGesture: false);
|
||||
},
|
||||
),
|
||||
]),
|
||||
@@ -622,6 +624,8 @@ class _LocalFavoritesPageState extends State<_LocalFavoritesPage> {
|
||||
id: c.id,
|
||||
sourceKey: c.sourceKey,
|
||||
),
|
||||
enableIOSGesture: false,
|
||||
iosFullScreenGesture: false,
|
||||
);
|
||||
},
|
||||
),
|
||||
@@ -647,6 +651,8 @@ class _LocalFavoritesPageState extends State<_LocalFavoritesPage> {
|
||||
id: c.id,
|
||||
sourceKey: c.sourceKey,
|
||||
),
|
||||
enableIOSGesture: false,
|
||||
iosFullScreenGesture: false,
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
@@ -37,6 +37,8 @@ class _ImageFavoritesItemState extends State<_ImageFavoritesItem> {
|
||||
initialEp: ep,
|
||||
initialPage: page,
|
||||
),
|
||||
enableIOSGesture: false,
|
||||
iosFullScreenGesture: false,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -244,6 +244,8 @@ class _ImageFavoritesPhotoViewState extends State<ImageFavoritesPhotoView> {
|
||||
initialEp: ep,
|
||||
initialPage: page,
|
||||
),
|
||||
enableIOSGesture: false,
|
||||
iosFullScreenGesture: false,
|
||||
);
|
||||
},
|
||||
),
|
||||
|
||||
@@ -252,9 +252,10 @@ class _SettingsPageState extends State<SettingsPage> implements PopEntry {
|
||||
if (!App.isIOS) {
|
||||
return;
|
||||
}
|
||||
if (event.position.dx < 20) {
|
||||
gestureRecognizer.addPointer(event);
|
||||
if (currentPage == -1) {
|
||||
return;
|
||||
}
|
||||
gestureRecognizer.addPointer(event);
|
||||
}
|
||||
|
||||
Widget buildLeft() {
|
||||
|
||||
Reference in New Issue
Block a user