Skip to content

FIX: More like a workaround for issue https://github.com/woltapp/wolt… #375

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import 'package:wolt_modal_sheet/wolt_modal_sheet.dart';
/// scrolls through the content. Utilizing the [Flow] widget, it listens to the current scroll
/// position and soft keyboard closing events, then, performs transformations to achieve the
/// desired effects on the top bar, such as fading in/out and translating vertically.
class WoltModalSheetTopBarFlow extends StatelessWidget {
class WoltModalSheetTopBarFlow extends StatefulWidget {
final ScrollController scrollController;
final GlobalKey titleKey;
final SliverWoltModalSheetPage page;
Expand All @@ -29,29 +29,84 @@ class WoltModalSheetTopBarFlow extends StatelessWidget {
Key? key,
}) : super(key: key);

@override
_WoltModalSheetTopBarFlowState createState() =>
_WoltModalSheetTopBarFlowState();
}

class _WoltModalSheetTopBarFlowState extends State<WoltModalSheetTopBarFlow> {
double _currentScrollOffset = 0.0;
bool _scrollUpdateScheduled = false;

@override
void initState() {
super.initState();
// Initialize with current offset if possible
if (widget.scrollController.hasClients) {
_currentScrollOffset = widget.scrollController.position.pixels;
}
widget.scrollController.addListener(_scrollListener);
}

@override
void didUpdateWidget(covariant WoltModalSheetTopBarFlow oldWidget) {
super.didUpdateWidget(oldWidget);
if (widget.scrollController != oldWidget.scrollController) {
oldWidget.scrollController.removeListener(_scrollListener);
// Initialize with new controller's offset if possible
if (widget.scrollController.hasClients) {
_currentScrollOffset = widget.scrollController.position.pixels;
} else {
_currentScrollOffset = 0.0; // Reset if no clients
}
widget.scrollController.addListener(_scrollListener);
}
// Update offset immediately if controller has clients and offset differs
if (widget.scrollController.hasClients &&
_currentScrollOffset != widget.scrollController.position.pixels) {
_scrollListener();
}
}

void _scrollListener() {
// Throttle updates to post-frame to avoid layout dirties during hit tests
if (!widget.scrollController.hasClients) return;
final newOffset = widget.scrollController.position.pixels;
if (_currentScrollOffset == newOffset) return;
_currentScrollOffset = newOffset;
if (!_scrollUpdateScheduled) {
_scrollUpdateScheduled = true;
WidgetsBinding.instance.addPostFrameCallback((_) {
if (mounted) setState(() {});
_scrollUpdateScheduled = false;
});
}
}

@override
Widget build(BuildContext context) {
final themeData = Theme.of(context).extension<WoltModalSheetThemeData>();
final defaultThemeData = WoltModalSheetDefaultThemeData(context);
final topBarHeight = page.navBarHeight ??
final topBarHeight = widget.page.navBarHeight ??
themeData?.navBarHeight ??
defaultThemeData.navBarHeight;
final heroImageHeight = page.heroImage == null
final heroImageHeight = widget.page.heroImage == null
? 0.0
: (page.heroImageHeight ??
: (widget.page.heroImageHeight ??
themeData?.heroImageHeight ??
defaultThemeData.heroImageHeight);

return Flow(
delegate: _TopBarFlowDelegate(
topBarHeight: topBarHeight,
heroImageHeight: heroImageHeight,
scrollController: scrollController,
titleKey: titleKey,
softKeyboardClosedListenable: softKeyboardClosedListenable,
scrollAnimationStyle: scrollAnimationStyle,
scrollController: widget.scrollController,
titleKey: widget.titleKey,
softKeyboardClosedListenable: widget.softKeyboardClosedListenable,
scrollAnimationStyle: widget.scrollAnimationStyle,
currentScrollOffset: _currentScrollOffset,
),
children: [WoltModalSheetTopBar(page: page)],
children: [WoltModalSheetTopBar(page: widget.page)],
);
}
}
Expand All @@ -63,6 +118,7 @@ class _TopBarFlowDelegate extends FlowDelegate {
final GlobalKey titleKey;
final ValueListenable<SoftKeyboardClosedEvent> softKeyboardClosedListenable;
final WoltModalSheetScrollAnimationStyle scrollAnimationStyle;
final double currentScrollOffset;

_TopBarFlowDelegate({
required this.topBarHeight,
Expand All @@ -71,15 +127,14 @@ class _TopBarFlowDelegate extends FlowDelegate {
required this.titleKey,
required this.scrollAnimationStyle,
required this.softKeyboardClosedListenable,
required this.currentScrollOffset,
}) : super(
repaint: Listenable.merge([
scrollController,
softKeyboardClosedListenable,
]),
);

double get currentScrollOffset => scrollController.position.pixels;

@override
void paintChildren(FlowPaintingContext context) {
final pageTitleHeight = titleKey.currentContext!.size!.height;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:wolt_modal_sheet/src/content/components/paginating_group/wolt_modal_sheet_page_transition_state.dart';
import 'package:wolt_modal_sheet/wolt_modal_sheet.dart';
import 'package:wolt_modal_sheet/src/widgets/pixel_slide_transition.dart';

class MainContentAnimatedBuilder extends StatefulWidget {
final AnimationController controller;
Expand Down Expand Up @@ -70,7 +71,7 @@ class _MainContentAnimatedBuilderState
opacity: pageTransitionState
.mainContentOpacity(controller, widget.paginationAnimationStyle)
.value,
child: SlideTransition(
child: PixelSlideTransition(
position: pageTransitionState.mainContentSlidePosition(
controller,
widget.paginationAnimationStyle,
Expand Down
6 changes: 4 additions & 2 deletions lib/src/modal_type/wolt_bottom_sheet_type.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'dart:math';

import 'package:flutter/material.dart';
import 'package:wolt_modal_sheet/src/widgets/pixel_slide_transition.dart';
import 'package:wolt_modal_sheet/wolt_modal_sheet.dart';

/// A customizable bottom sheet modal that extends [WoltModalType].
Expand Down Expand Up @@ -124,7 +125,7 @@ class WoltBottomSheetType extends WoltModalType {
/// [secondaryAnimation] coordinates with the transitions of other routes.
/// [child] is the content widget to be animated.
///
/// Returns a `SlideTransition` widget that manages the modal's entrance animation.
/// Returns a `PixelSlideTransition` widget that manages the modal's entrance animation.
@override
Widget buildTransitions(
BuildContext context,
Expand All @@ -151,7 +152,8 @@ class WoltBottomSheetType extends WoltModalType {
),
);

return SlideTransition(position: positionAnimation, child: child);
// Use PixelSlideTransition to avoid RenderFractionalTranslation layout asserts
return PixelSlideTransition(position: positionAnimation, child: child);
}

/// Provides a way to create a new `WoltBottomSheetType` instance with modified properties.
Expand Down
3 changes: 2 additions & 1 deletion lib/src/modal_type/wolt_dialog_type.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import 'dart:math';
import 'package:flutter/material.dart';
import 'package:wolt_modal_sheet/src/utils/wolt_breakpoints.dart';
import 'package:wolt_modal_sheet/wolt_modal_sheet.dart';
import 'package:wolt_modal_sheet/src/widgets/pixel_slide_transition.dart';

/// A customizable dialog modal that extends [WoltModalType].
class WoltDialogType extends WoltModalType {
Expand Down Expand Up @@ -150,7 +151,7 @@ class WoltDialogType extends WoltModalType {

return FadeTransition(
opacity: alphaAnimation,
child: SlideTransition(position: positionAnimation, child: child),
child: PixelSlideTransition(position: positionAnimation, child: child),
);
}

Expand Down
3 changes: 2 additions & 1 deletion lib/src/modal_type/wolt_side_sheet_type.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import 'dart:math';
import 'package:flutter/material.dart';
import 'package:wolt_modal_sheet/src/utils/wolt_breakpoints.dart';
import 'package:wolt_modal_sheet/wolt_modal_sheet.dart';
import 'package:wolt_modal_sheet/src/widgets/pixel_slide_transition.dart';

/// A customizable side sheet modal that extends [WoltModalType].
class WoltSideSheetType extends WoltModalType {
Expand Down Expand Up @@ -168,7 +169,7 @@ class WoltSideSheetType extends WoltModalType {

return FadeTransition(
opacity: alphaAnimation,
child: SlideTransition(position: positionAnimation, child: child),
child: PixelSlideTransition(position: positionAnimation, child: child),
);
}

Expand Down
40 changes: 40 additions & 0 deletions lib/src/widgets/pixel_slide_transition.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import 'package:flutter/widgets.dart';

/// A slide transition that uses pixel-based translation (Transform.translate)
/// instead of FractionalTranslation, avoiding debugNeedsLayout asserts.
class PixelSlideTransition extends StatelessWidget {
/// An offset animation where values represent fractional (0.0 to 1.0) positions.
final Animation<Offset> position;

/// The widget child to be transformed.
final Widget child;

const PixelSlideTransition({
required this.position,
required this.child,
Key? key,
}) : super(key: key);

@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (context, constraints) {
return AnimatedBuilder(
animation: position,
builder: (context, child) {
final offset = position.value;
// Convert fractional offsets to pixel values
final dx = offset.dx * constraints.maxWidth;
final dy = offset.dy * constraints.maxHeight;
return Transform.translate(
offset: Offset(dx, dy),
transformHitTests: false,
child: child,
);
},
child: child,
);
},
);
}
}
22 changes: 16 additions & 6 deletions lib/src/wolt_modal_sheet_route.dart
Original file line number Diff line number Diff line change
Expand Up @@ -113,12 +113,22 @@ class WoltModalSheetRoute<T> extends PageRoute<T> {
Animation<double> secondaryAnimation,
Widget child,
) {
final modalType = _determineCurrentModalType(context);
return modalType.buildTransitions(
context,
animation,
secondaryAnimation,
child,
// Prevent pointer events (e.g., mouse scroll) during entrance/exit animations
return AnimatedBuilder(
animation: animation,
child: child,
builder: (context, child) {
final modalType = _determineCurrentModalType(context);
final transition = modalType.buildTransitions(
context,
animation,
secondaryAnimation,
child!,
);
final isAnimating = animation.status != AnimationStatus.completed &&
animation.status != AnimationStatus.dismissed;
return AbsorbPointer(absorbing: isAnimating, child: transition);
},
);
}

Expand Down