Skip to content

Commit

Permalink
Merge pull request #119 from woltapp/fix-top-bar-visibility-when-keyb…
Browse files Browse the repository at this point in the history
…oard-disappears

[Issue-96] Fix TopBar Widget keeps being visible after Keyboard hides
  • Loading branch information
ulusoyca authored Jan 10, 2024
2 parents 9a0b275 + e6a906a commit b22554c
Show file tree
Hide file tree
Showing 7 changed files with 175 additions and 76 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,41 +7,24 @@ import 'package:wolt_modal_sheet/wolt_modal_sheet.dart';
///
/// This widget is responsible for displaying the main content of the scrollable modal sheet.
/// It handles the scroll behavior, page layout, and interactions within the modal sheet.
class WoltModalSheetMainContent extends StatefulWidget {
final ValueNotifier<double> currentScrollPosition;
class WoltModalSheetMainContent extends StatelessWidget {
final ScrollController? scrollController;
final GlobalKey pageTitleKey;
final SliverWoltModalSheetPage page;
final WoltModalType woltModalType;

const WoltModalSheetMainContent({
required this.currentScrollPosition,
required this.scrollController,
required this.pageTitleKey,
required this.page,
required this.woltModalType,
Key? key,
}) : super(key: key);

@override
State<WoltModalSheetMainContent> createState() =>
_WoltModalSheetMainContentState();
}

class _WoltModalSheetMainContentState extends State<WoltModalSheetMainContent> {
late ScrollController scrollController;

@override
void initState() {
super.initState();
scrollController = widget.page.scrollController ??
ScrollController(
initialScrollOffset: widget.currentScrollPosition.value);
}

@override
Widget build(BuildContext context) {
final themeData = Theme.of(context).extension<WoltModalSheetThemeData>();
final defaultThemeData = WoltModalSheetDefaultThemeData(context);
final page = widget.page;
final heroImageHeight = page.heroImage == null
? 0.0
: (page.heroImageHeight ??
Expand Down Expand Up @@ -85,7 +68,7 @@ class _WoltModalSheetMainContentState extends State<WoltModalSheetMainContent> {
} else {
final pageTitle = page.pageTitle;
return KeyedSubtree(
key: widget.pageTitleKey,
key: pageTitleKey,
child: pageTitle ?? const SizedBox.shrink(),
);
}
Expand All @@ -101,24 +84,12 @@ class _WoltModalSheetMainContentState extends State<WoltModalSheetMainContent> {
),
],
);
return NotificationListener<ScrollNotification>(
onNotification: (scrollNotification) {
final isVerticalScrollNotification =
scrollNotification is ScrollUpdateNotification &&
scrollNotification.metrics.axis == Axis.vertical;
if (isVerticalScrollNotification) {
widget.currentScrollPosition.value =
scrollNotification.metrics.pixels;
}
return false;
},
child: Padding(
// The scroll view should be padded by the height of the top bar layer if it's always
// visible. Otherwise, over scroll effect will not be visible due to the top bar layer.
padding:
EdgeInsets.only(top: isTopBarLayerAlwaysVisible ? topBarHeight : 0),
child: scrollView,
),
return Padding(
// The scroll view should be padded by the height of the top bar layer if it's always
// visible. Otherwise, over scroll effect will not be visible due to the top bar layer.
padding:
EdgeInsets.only(top: isTopBarLayerAlwaysVisible ? topBarHeight : 0),
child: scrollView,
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,30 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:wolt_modal_sheet/src/content/components/main_content/wolt_modal_sheet_top_bar.dart';
import 'package:wolt_modal_sheet/src/theme/wolt_modal_sheet_default_theme_data.dart';
import 'package:wolt_modal_sheet/src/utils/soft_keyboard_closed_event.dart';
import 'package:wolt_modal_sheet/src/utils/wolt_layout_transformation_utils.dart';
import 'package:wolt_modal_sheet/wolt_modal_sheet.dart';

/// `WoltModalSheetTopBarFlow` controls the top bar behavior within the modal sheet page
/// provided by the [WoltModalSheetPage] when `isTopBarLayerAlwaysVisible` is set to true.
/// [WoltModalSheetTopBarFlow] controls the top bar behavior within the modal sheet page
/// provided by the [WoltModalSheetPage] when `isTopBarLayerAlwaysVisible` is set to false.
///
/// It is responsible for the positioning, translation, and opacity of the top bar as the user
/// scrolls through the content. Utilizing the [Flow] widget, it listens to the current scroll
/// position and performs transformations to achieve the desired effects on the top bar, such as
/// fading in/out and translating vertically.
/// 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 {
final ValueListenable<double> currentScrollPositionListenable;
final ScrollController scrollController;
final GlobalKey titleKey;
final double topBarTranslationYAmountInPx;
final SliverWoltModalSheetPage page;
final ValueListenable<SoftKeyboardClosedEvent> softKeyboardClosedListenable;

const WoltModalSheetTopBarFlow({
required this.page,
required this.currentScrollPositionListenable,
required this.scrollController,
required this.titleKey,
required this.topBarTranslationYAmountInPx,
required this.softKeyboardClosedListenable,
Key? key,
}) : super(key: key);

Expand All @@ -43,10 +46,10 @@ class WoltModalSheetTopBarFlow extends StatelessWidget {
delegate: _TopBarFlowDelegate(
topBarHeight: topBarHeight,
heroImageHeight: heroImageHeight,
currentScrollPositionListenable: currentScrollPositionListenable,
scrollController: scrollController,
titleKey: titleKey,
topBarTranslationYAmountInPx: topBarTranslationYAmountInPx,
buildContext: context,
softKeyboardClosedListenable: softKeyboardClosedListenable,
),
children: [WoltModalSheetTopBar(page: page)],
);
Expand All @@ -56,21 +59,26 @@ class WoltModalSheetTopBarFlow extends StatelessWidget {
class _TopBarFlowDelegate extends FlowDelegate {
final double topBarHeight;
final double heroImageHeight;
final ValueListenable<double> currentScrollPositionListenable;
final ScrollController scrollController;
final GlobalKey titleKey;
final double topBarTranslationYAmountInPx;
final BuildContext buildContext;
final ValueListenable<SoftKeyboardClosedEvent> softKeyboardClosedListenable;

_TopBarFlowDelegate({
required this.topBarHeight,
required this.heroImageHeight,
required this.currentScrollPositionListenable,
required this.scrollController,
required this.titleKey,
required this.topBarTranslationYAmountInPx,
required this.buildContext,
}) : super(repaint: currentScrollPositionListenable);
required this.softKeyboardClosedListenable,
}) : super(
repaint: Listenable.merge([
scrollController,
softKeyboardClosedListenable,
]),
);

double get currentScrollPosition => currentScrollPositionListenable.value;
double get currentScrollOffset => scrollController.position.pixels;

@override
void paintChildren(FlowPaintingContext context) {
Expand All @@ -86,7 +94,7 @@ class _TopBarFlowDelegate extends FlowDelegate {
WoltLayoutTransformationUtils.calculateTransformationValue(
rangeInPx: 8 + pageTitleHeight,
progressInRangeInPx:
currentScrollPosition - topBarTranslationYAndOpacityStartPoint,
currentScrollOffset - topBarTranslationYAndOpacityStartPoint,
startValue: topBarTranslationYStart,
endValue: topBarTranslationYEnd,
);
Expand All @@ -96,7 +104,7 @@ class _TopBarFlowDelegate extends FlowDelegate {
WoltLayoutTransformationUtils.calculateTransformationValue(
rangeInPx: 8,
progressInRangeInPx:
currentScrollPosition - topBarTranslationYAndOpacityStartPoint,
currentScrollOffset - topBarTranslationYAndOpacityStartPoint,
startValue: 0.0,
endValue: 1.0,
);
Expand All @@ -113,9 +121,11 @@ class _TopBarFlowDelegate extends FlowDelegate {
bool shouldRepaint(covariant _TopBarFlowDelegate oldDelegate) {
return heroImageHeight != oldDelegate.heroImageHeight ||
titleKey != oldDelegate.titleKey ||
currentScrollPosition != oldDelegate.currentScrollPosition ||
currentScrollOffset != oldDelegate.currentScrollOffset ||
topBarTranslationYAmountInPx !=
oldDelegate.topBarTranslationYAmountInPx ||
softKeyboardClosedListenable.value !=
oldDelegate.softKeyboardClosedListenable.value ||
topBarHeight != oldDelegate.topBarHeight;
}
}
Original file line number Diff line number Diff line change
@@ -1,21 +1,30 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:wolt_modal_sheet/src/theme/wolt_modal_sheet_default_theme_data.dart';
import 'package:wolt_modal_sheet/src/utils/soft_keyboard_closed_event.dart';
import 'package:wolt_modal_sheet/src/utils/wolt_layout_transformation_utils.dart';
import 'package:wolt_modal_sheet/wolt_modal_sheet.dart';

/// This class represents the top bar title behavior within a modal sheet page.
/// [WoltModalSheetTopBarTitleFlow] controls the top bar title behavior within the modal sheet page
/// provided by the [WoltModalSheetPage] when `isTopBarLayerAlwaysVisible` is set to false.
///
/// It is responsible for the positioning, translation, and opacity of the top bar title as the user
/// 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 title, such as fading in/out and translating vertically.
class WoltModalSheetTopBarTitleFlow extends StatelessWidget {
final ValueListenable<double> currentScrollPositionListenable;
final ScrollController scrollController;
final GlobalKey titleKey;
final SliverWoltModalSheetPage page;
final Widget topBarTitle;
final ValueListenable<SoftKeyboardClosedEvent> softKeyboardClosedListenable;

const WoltModalSheetTopBarTitleFlow({
required this.page,
required this.currentScrollPositionListenable,
required this.scrollController,
required this.titleKey,
required this.topBarTitle,
required this.softKeyboardClosedListenable,
Key? key,
}) : super(key: key);

Expand All @@ -37,9 +46,9 @@ class WoltModalSheetTopBarTitleFlow extends StatelessWidget {
delegate: _TopBarTitleFlowDelegate(
topBarHeight: topBarHeight,
heroImageHeight: heroImageHeight,
currentScrollPositionListenable: currentScrollPositionListenable,
scrollController: scrollController,
titleKey: titleKey,
buildContext: context,
softKeyboardClosedNotifier: softKeyboardClosedListenable,
),
children: [Center(child: topBarTitle)],
);
Expand All @@ -49,19 +58,24 @@ class WoltModalSheetTopBarTitleFlow extends StatelessWidget {
class _TopBarTitleFlowDelegate extends FlowDelegate {
final double topBarHeight;
final double heroImageHeight;
final ValueListenable<double> currentScrollPositionListenable;
final ScrollController scrollController;
final GlobalKey titleKey;
final BuildContext buildContext;
final ValueListenable<SoftKeyboardClosedEvent> softKeyboardClosedNotifier;

_TopBarTitleFlowDelegate({
required this.topBarHeight,
required this.heroImageHeight,
required this.currentScrollPositionListenable,
required this.scrollController,
required this.titleKey,
required this.buildContext,
}) : super(repaint: currentScrollPositionListenable);
required this.softKeyboardClosedNotifier,
}) : super(
repaint: Listenable.merge([
scrollController,
softKeyboardClosedNotifier,
]),
);

double get currentScrollPosition => currentScrollPositionListenable.value;
double get currentScrollPosition => scrollController.position.pixels;

@override
void paintChildren(FlowPaintingContext context) {
Expand Down Expand Up @@ -108,7 +122,10 @@ class _TopBarTitleFlowDelegate extends FlowDelegate {
bool shouldRepaint(covariant _TopBarTitleFlowDelegate oldDelegate) {
return heroImageHeight != oldDelegate.heroImageHeight ||
titleKey != oldDelegate.titleKey ||
currentScrollPosition != oldDelegate.currentScrollPosition ||
scrollController.position.pixels !=
oldDelegate.scrollController.position.pixels ||
softKeyboardClosedNotifier.value !=
oldDelegate.softKeyboardClosedNotifier.value ||
topBarHeight != oldDelegate.topBarHeight;
}
}
Loading

0 comments on commit b22554c

Please sign in to comment.