Skip to content

Commit

Permalink
Use notification listener only in gesture detector
Browse files Browse the repository at this point in the history
  • Loading branch information
ulusoyca committed Jul 31, 2024
1 parent 4a498a0 commit 6680510
Show file tree
Hide file tree
Showing 7 changed files with 81 additions and 200 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,104 +13,15 @@ class WoltModalSheetMainContent extends StatelessWidget {
final SliverWoltModalSheetPage page;
final WoltModalType woltModalType;
final WoltModalSheetScrollAnimationStyle scrollAnimationStyle;
final WoltModalSheetRoute route;
final VoidCallback? onModalDismissedWithDrag;
final GlobalKey modalContentKey;

const WoltModalSheetMainContent({
required this.scrollController,
required this.pageTitleKey,
required this.page,
required this.woltModalType,
required this.scrollAnimationStyle,
required this.route,
this.onModalDismissedWithDrag,
required this.modalContentKey,
Key? key,
}) : super(key: key);
RenderBox get _renderBox =>
modalContentKey.currentContext!.findRenderObject()! as RenderBox;

double get _childHeight => _renderBox.size.height;
bool get _shouldDragContent =>
(page.contentDraggable ?? false) && woltModalType is WoltBottomSheetType;

AnimationController get _animationController => route.animationController!;

double get _minFlingVelocity => woltModalType.minFlingVelocity;

bool get _isDismissUnderway =>
_animationController.status == AnimationStatus.reverse;

bool get _isDismissed => _animationController.isDismissed;

WoltModalDismissDirection? get _dismissDirection =>
woltModalType.dismissDirection;

void _handleVerticalDragUpdate(
DragUpdateDetails details, BuildContext context) {
if (_isDismissUnderway || _isDismissed) {
return;
}

final deltaDiff = details.primaryDelta! / _childHeight;
_animationController.value -= deltaDiff;

if (_dismissDirection == WoltModalDismissDirection.down) {
_animationController.value -= deltaDiff;
} else if (_dismissDirection == WoltModalDismissDirection.up) {
_animationController.value += deltaDiff;
}
}

void _handleVerticalDragEnd(BuildContext context, DragEndDetails details) {
if (_isDismissUnderway || _isDismissed) {
return;
}
bool isClosing = false;
bool isDraggingUpward = details.velocity.pixelsPerSecond.dy < 0;
bool isDraggingDownward = details.velocity.pixelsPerSecond.dy > 0;
final isDismissUp = _dismissDirection?.isUp ?? false;
final isDismissDown = _dismissDirection?.isDown ?? false;
final double flingVelocity =
details.velocity.pixelsPerSecond.dy / _childHeight;

if (isDraggingUpward && isDismissUp) {
if (details.velocity.pixelsPerSecond.dy.abs() > _minFlingVelocity) {
_animationController.fling(velocity: flingVelocity);
if (flingVelocity > 0.0) {
isClosing = true;
}
}
}

if (isDraggingDownward && isDismissDown) {
if (details.velocity.pixelsPerSecond.dy > _minFlingVelocity) {
_animationController.fling(velocity: flingVelocity * -1.0);
if (flingVelocity < 0.0) {
isClosing = true;
}
}
}

if (_animationController.value < woltModalType.closeProgressThreshold) {
if (_animationController.value > 0.0) {
_animationController.fling(velocity: -1.0);
}
isClosing = true;
} else {
_animationController.forward();
}

if (isClosing && route.isCurrent) {
final onModalDismissedWithDrag = this.onModalDismissedWithDrag;
if (onModalDismissedWithDrag != null) {
onModalDismissedWithDrag();
} else {
Navigator.pop(context);
}
}
}

@override
Widget build(BuildContext context) {
Expand All @@ -137,77 +48,53 @@ class WoltModalSheetMainContent extends StatelessWidget {
final isNonScrollingPage = page is NonScrollingWoltModalSheetPage;
final shouldFillRemaining = woltModalType.forceMaxHeight ||
(page.forceMaxHeight && !isNonScrollingPage);

final scrollView = NotificationListener(
onNotification: _shouldDragContent
? (ScrollNotification notification) {
if (notification is OverscrollNotification) {
if (notification.dragDetails != null) {
_handleVerticalDragUpdate(notification.dragDetails!, context);
}
}
if (notification is ScrollEndNotification) {
if (notification.dragDetails != null) {
_handleVerticalDragEnd(context, notification.dragDetails!);
final scrollView = CustomScrollView(
shrinkWrap: true,
physics: themeData?.mainContentScrollPhysics ??
defaultThemeData.mainContentScrollPhysics,
controller: scrollController,
slivers: [
if (!isNonScrollingPage)
SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) {
if (index == 0) {
final heroImage = page.heroImage;
return heroImage != null
? WoltModalSheetHeroImage(
topBarHeight: topBarHeight,
heroImage: heroImage,
heroImageHeight: heroImageHeight,
scrollAnimationStyle: scrollAnimationStyle,
)
// If top bar layer is always visible, the padding is explicitly added to the
// scroll view since top bar will not be integrated to scroll view at all.
// Otherwise, we implicitly create a spacing as a part of the scroll view.
: SizedBox(
height:
isTopBarLayerAlwaysVisible ? 0 : topBarHeight);
} else {
final pageTitle = page.pageTitle;
return KeyedSubtree(
key: pageTitleKey,
child: pageTitle ?? const SizedBox.shrink(),
);
}
}
if (notification is ScrollStartNotification) {
print('start');
}

return true;
}
: null,
child: CustomScrollView(
shrinkWrap: true,
physics: _shouldDragContent
? const ClampingScrollPhysics()
: (themeData?.mainContentScrollPhysics ??
defaultThemeData.mainContentScrollPhysics),
controller: scrollController,
slivers: [
if (!isNonScrollingPage)
SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) {
if (index == 0) {
final heroImage = page.heroImage;
return heroImage != null
? WoltModalSheetHeroImage(
topBarHeight: topBarHeight,
heroImage: heroImage,
heroImageHeight: heroImageHeight,
scrollAnimationStyle: scrollAnimationStyle,
)
// If top bar layer is always visible, the padding is explicitly added to the
// scroll view since top bar will not be integrated to scroll view at all.
// Otherwise, we implicitly create a spacing as a part of the scroll view.
: SizedBox(
height:
isTopBarLayerAlwaysVisible ? 0 : topBarHeight);
} else {
final pageTitle = page.pageTitle;
return KeyedSubtree(
key: pageTitleKey,
child: pageTitle ?? const SizedBox.shrink(),
);
}
},
childCount: 2,
),
),
if (page.mainContentSliversBuilder == null)
// ignore: deprecated_member_use_from_same_package
...page.mainContentSlivers!
else
...page.mainContentSliversBuilder!(context),
if (shouldFillRemaining)
const SliverFillRemaining(
hasScrollBody: false,
child: SizedBox.shrink(),
},
childCount: 2,
),
],
),
),
if (page.mainContentSliversBuilder == null)
// ignore: deprecated_member_use_from_same_package
...page.mainContentSlivers!
else
...page.mainContentSliversBuilder!(context),
if (shouldFillRemaining)
const SliverFillRemaining(
hasScrollBody: false,
child: SizedBox.shrink(),
),
],
);
return Padding(
// The scroll view should be padded by the height of the top bar layer if it's always
Expand Down
9 changes: 0 additions & 9 deletions lib/src/content/wolt_modal_sheet_animated_switcher.dart
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,13 @@ class WoltModalSheetAnimatedSwitcher extends StatefulWidget {
final WoltModalType woltModalType;
final double sheetWidth;
final bool showDragHandle;
final WoltModalSheetRoute route;
final VoidCallback? onModalDismissedWithDrag;
final GlobalKey modalContentKey;

const WoltModalSheetAnimatedSwitcher({
required this.pages,
required this.pageIndex,
required this.woltModalType,
required this.sheetWidth,
required this.showDragHandle,
required this.route,
this.onModalDismissedWithDrag,
required this.modalContentKey,
Key? key,
}) : assert(pageIndex >= 0 && pageIndex < pages.length),
super(key: key);
Expand Down Expand Up @@ -492,9 +486,6 @@ class _WoltModalSheetAnimatedSwitcherState
scrollController: scrollController,
page: _page,
woltModalType: widget.woltModalType,
route: widget.route,
onModalDismissedWithDrag: widget.onModalDismissedWithDrag,
modalContentKey: widget.modalContentKey,
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ class NonScrollingWoltModalSheetPage extends SliverWoltModalSheetPage {
super.topBarTitle,
super.navBarHeight,
super.useSafeArea,
super.contentDraggable,
}) : super(
isTopBarLayerAlwaysVisible: hasTopBarLayer,
mainContentSliversBuilder: (_) => [
Expand Down
11 changes: 0 additions & 11 deletions lib/src/modal_page/sliver_wolt_modal_sheet_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -233,12 +233,6 @@ class SliverWoltModalSheetPage {
/// notch and system gesture areas.
final bool? useSafeArea;

/// Controls the draggability of the bottom sheet content. This setting overrides the value provided
/// via [WoltModalSheet.show] specifically for this page when the modal is displayed as a bottom sheet.
final bool? contentDraggable;



/// Creates a page to be built within [WoltScrollableModalSheet].
const SliverWoltModalSheetPage({
this.mainContentSlivers,
Expand All @@ -264,7 +258,6 @@ class SliverWoltModalSheetPage {
this.isTopBarLayerAlwaysVisible,
this.resizeToAvoidBottomInset,
this.useSafeArea,
this.contentDraggable,
}) : assert(!(topBar != null && hasTopBarLayer == false),
"When topBar is provided, hasTopBarLayer must not be false"),
assert(
Expand Down Expand Up @@ -294,7 +287,6 @@ class SliverWoltModalSheetPage {
Widget? trailingNavBarWidget,
bool? resizeToAvoidBottomInset,
bool? useSafeArea,
bool? contentDraggable,
Widget? child,
}) {
return SliverWoltModalSheetPage(
Expand Down Expand Up @@ -323,7 +315,6 @@ class SliverWoltModalSheetPage {
resizeToAvoidBottomInset:
resizeToAvoidBottomInset ?? this.resizeToAvoidBottomInset,
useSafeArea: useSafeArea ?? this.useSafeArea,
contentDraggable: contentDraggable ?? this.contentDraggable,
);
}

Expand Down Expand Up @@ -355,7 +346,6 @@ class SliverWoltModalSheetPage {
Widget? trailingNavBarWidget,
bool? resizeToAvoidBottomInset,
bool? useSafeArea,
bool? contentDraggable,
Widget? child,
}) {
return SliverWoltModalSheetPage(
Expand Down Expand Up @@ -384,7 +374,6 @@ class SliverWoltModalSheetPage {
trailingNavBarWidget: trailingNavBarWidget ?? this.trailingNavBarWidget,
resizeToAvoidBottomInset:
resizeToAvoidBottomInset ?? this.resizeToAvoidBottomInset,
contentDraggable: contentDraggable ?? this.contentDraggable,
useSafeArea: useSafeArea ?? this.useSafeArea,
);
}
Expand Down
1 change: 0 additions & 1 deletion lib/src/modal_page/wolt_modal_sheet_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@ class WoltModalSheetPage extends SliverWoltModalSheetPage {
super.trailingNavBarWidget,
super.topBar,
super.useSafeArea,
super.contentDraggable,
}) : super(
mainContentSliversBuilder: (context) => [
SliverToBoxAdapter(child: child),
Expand Down
51 changes: 36 additions & 15 deletions lib/src/widgets/wolt_modal_sheet_content_gesture_detector.dart
Original file line number Diff line number Diff line change
Expand Up @@ -48,28 +48,49 @@ class WoltModalSheetContentGestureDetector extends StatelessWidget {
final isVertical = _dismissDirection?.isVertical ?? false;
final isHorizontal = _dismissDirection?.isHorizontal ?? false;

return GestureDetector(
excludeFromSemantics: true,
onVerticalDragUpdate: (details) => canDragToDismiss && isVertical
? _handleVerticalDragUpdate(details)
: null,
onVerticalDragEnd: (details) => canDragToDismiss && isVertical
? _handleVerticalDragEnd(context, details)
: null,
onHorizontalDragUpdate: (details) => canDragToDismiss && isHorizontal
? _handleHorizontalDragUpdate(context, details)
: null,
onHorizontalDragEnd: (details) => canDragToDismiss && isHorizontal
? _handleHorizontalDragEnd(context, details)
: null,
child: child,
return NotificationListener(
onNotification: (notification) {
if (notification is OverscrollNotification &&
notification.dragDetails != null &&
canDragToDismiss) {
isVertical
? _handleVerticalDragUpdate(notification.dragDetails!)
: _handleHorizontalDragUpdate(context, notification.dragDetails!);
_handleVerticalDragUpdate(notification.dragDetails!);
}
if (notification is ScrollEndNotification &&
notification.dragDetails != null &&
canDragToDismiss) {
isVertical
? _handleVerticalDragEnd(context, notification.dragDetails!)
: _handleHorizontalDragEnd(context, notification.dragDetails!);
}
return true;
},
child: GestureDetector(
excludeFromSemantics: true,
onVerticalDragUpdate: (details) => canDragToDismiss && isVertical
? _handleVerticalDragUpdate(details)
: null,
onVerticalDragEnd: (details) => canDragToDismiss && isVertical
? _handleVerticalDragEnd(context, details)
: null,
onHorizontalDragUpdate: (details) => canDragToDismiss && isHorizontal
? _handleHorizontalDragUpdate(context, details)
: null,
onHorizontalDragEnd: (details) => canDragToDismiss && isHorizontal
? _handleHorizontalDragEnd(context, details)
: null,
child: child,
),
);
}

void _handleVerticalDragUpdate(DragUpdateDetails details) {
if (_isDismissUnderway || _isDismissed) {
return;
}

final deltaDiff = details.primaryDelta! / _childHeight;
if (_dismissDirection == WoltModalDismissDirection.down) {
_animationController.value -= deltaDiff;
Expand Down
Loading

0 comments on commit 6680510

Please sign in to comment.