Skip to content

Commit

Permalink
Remove keyboard visibility listener package and use widget binding pb…
Browse files Browse the repository at this point in the history
…server
  • Loading branch information
ulusoyca committed Aug 14, 2024
1 parent d97fcdb commit 8d4efac
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 47 deletions.
53 changes: 7 additions & 46 deletions lib/src/content/wolt_modal_sheet_animated_switcher.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
import 'dart:async';

import 'package:flutter/material.dart';
import 'package:flutter_keyboard_visibility/flutter_keyboard_visibility.dart';
import 'package:wolt_modal_sheet/src/content/components/main_content/wolt_modal_sheet_main_content.dart';
import 'package:wolt_modal_sheet/src/content/components/main_content/wolt_modal_sheet_top_bar.dart';
import 'package:wolt_modal_sheet/src/content/components/main_content/wolt_modal_sheet_top_bar_flow.dart';
Expand All @@ -11,7 +8,7 @@ import 'package:wolt_modal_sheet/src/content/components/paginating_group/paginat
import 'package:wolt_modal_sheet/src/content/components/paginating_group/wolt_modal_sheet_page_transition_state.dart';
import 'package:wolt_modal_sheet/src/content/wolt_modal_sheet_layout.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_keyboard_closure_listener_mixin.dart';
import 'package:wolt_modal_sheet/src/widgets/wolt_navigation_toolbar.dart';
import 'package:wolt_modal_sheet/src/widgets/wolt_sticky_action_bar_wrapper.dart';
import 'package:wolt_modal_sheet/wolt_modal_sheet.dart';
Expand Down Expand Up @@ -40,12 +37,13 @@ class WoltModalSheetAnimatedSwitcher extends StatefulWidget {

class _WoltModalSheetAnimatedSwitcherState
extends State<WoltModalSheetAnimatedSwitcher>
with TickerProviderStateMixin {
with
TickerProviderStateMixin,
WidgetsBindingObserver,
WoltKeyboardClosureListenerMixin {
PaginatingWidgetsGroup? _incomingPageWidgets;
PaginatingWidgetsGroup? _outgoingPageWidgets;

static const int _maxKeyboardAnimationDuration = 250;

int get _pagesCount => widget.pages.length;

int get _pageIndex => widget.pageIndex;
Expand Down Expand Up @@ -84,25 +82,6 @@ class _WoltModalSheetAnimatedSwitcherState
ValueNotifier<double> get _currentPageScrollPosition =>
_scrollPositions[_pageIndex];

/// Subscription for discovering the state of the soft-keyboard visibility
late StreamSubscription<bool> _softKeyboardVisibilitySubscription;

/// Value notifier for discovering when the soft-keyboard is dismissed. These events are
/// consumed by [WoltModalSheetTopBarFlow] and [WoltModalSheetTopBarTitleFlow] to trigger a
/// re-paint when keyboard is closing. This is needed to avoid the top bar from being stuck
/// when keyboard is closing.
///
/// By default, the top bar visibility is synced with the scroll controller position. The
/// [WoltModalSheetTopBarFlow] and [WoltModalSheetTopBarTitleFlow] paints the top bar according
/// to the scroll position changes.
///
/// When the keyboard appears the scroll controller receives scroll update events, which are
/// sent by the Flutter SDK. However, the keyboard closing events do not cause a change in the
/// scroll controller. Therefore, we need to manually trigger a re-paint when the keyboard is
/// closing.
final ValueNotifier<SoftKeyboardClosedEvent> _softKeyboardClosedNotifier =
ValueNotifier(const SoftKeyboardClosedEvent(eventId: 0));

bool _isForwardMove = true;

late bool _shouldAnimatePagination;
Expand All @@ -116,7 +95,6 @@ class _WoltModalSheetAnimatedSwitcherState
_resetScrollPositions();
_resetScrollControllers();
_subscribeToCurrentPageScrollPositionChanges();
_subscribeToSoftKeyboardClosedEvent();
}

void _resetGlobalKeys() {
Expand Down Expand Up @@ -154,22 +132,6 @@ class _WoltModalSheetAnimatedSwitcherState
}
}

void _subscribeToSoftKeyboardClosedEvent() {
_softKeyboardVisibilitySubscription =
KeyboardVisibilityController().onChange.listen((bool visible) async {
if (!visible) {
/// Wait for closing soft keyboard animation to finish before emitting new value.
await Future.delayed(
const Duration(milliseconds: _maxKeyboardAnimationDuration),
);
final int lastEventId = _softKeyboardClosedNotifier.value.eventId;
final newEventId = lastEventId + 1;
_softKeyboardClosedNotifier.value =
SoftKeyboardClosedEvent(eventId: newEventId);
}
});
}

@override
void didChangeDependencies() {
super.didChangeDependencies();
Expand Down Expand Up @@ -251,7 +213,6 @@ class _WoltModalSheetAnimatedSwitcherState
@override
void dispose() {
_animationController?.dispose();
_softKeyboardVisibilitySubscription.cancel();
for (final element in _scrollControllers) {
element.dispose();
}
Expand Down Expand Up @@ -355,7 +316,7 @@ class _WoltModalSheetAnimatedSwitcherState
scrollController: _currentPageScrollController,
titleKey: _pageTitleKey,
topBarTitle: topBarTitle,
softKeyboardClosedListenable: _softKeyboardClosedNotifier,
softKeyboardClosedListenable: softKeyboardClosureListenable,
);
}
}
Expand Down Expand Up @@ -396,7 +357,7 @@ class _WoltModalSheetAnimatedSwitcherState
page: _page,
scrollController: _currentPageScrollController,
titleKey: _pageTitleKey,
softKeyboardClosedListenable: _softKeyboardClosedNotifier,
softKeyboardClosedListenable: softKeyboardClosureListenable,
))
: const SizedBox.shrink(),
),
Expand Down
62 changes: 62 additions & 0 deletions lib/src/utils/wolt_keyboard_closure_listener_mixin.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:wolt_modal_sheet/src/utils/soft_keyboard_closed_event.dart';

/// Mixin [WoltKeyboardClosureListenerMixin] adds functionality to track the soft keyboard's
/// visibility within the application lifecycle. It leverages the [WidgetsBindingObserver]
/// to monitor changes in the UI metrics, particularly to detect when the keyboard is shown
/// or hidden.
///
/// When the keyboard transitions from visible to hidden, the mixin updates a [ValueNotifier]
/// with a new [SoftKeyboardClosedEvent], incrementing an event ID to signal that the keyboard
/// has closed. This can be used to trigger updates or actions when the keyboard hides,
/// such as resizing layouts or adjusting UI elements.
///
/// To use this mixin, include it in any [State] class of a [StatefulWidget] and ensure
/// to call `super.initState()` and `super.dispose()` to correctly manage the mixin's lifecycle.
mixin WoltKeyboardClosureListenerMixin<T extends StatefulWidget>
on State<T>, WidgetsBindingObserver {
bool _keyboardWasVisible = false;
late ValueNotifier<SoftKeyboardClosedEvent> _keyboardClosedNotifier;

/// Initializes the state, setting up the observer and initializing the notifier.
@override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
_keyboardClosedNotifier = ValueNotifier(const SoftKeyboardClosedEvent(
eventId: 0)); // Provide an appropriate initial event ID.
}

/// Cleans up by removing the observer to avoid memory leaks.
@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}

/// Reacts to changes in system metrics, particularly those affecting the bottom
/// view inset, which typically represents the soft keyboard. If the keyboard
/// was previously visible and is now hidden, it increments the event ID and updates
/// the notifier.
@override
void didChangeMetrics() {
super.didChangeMetrics();
final viewInsets = MediaQuery.of(context).viewInsets.bottom;
bool keyboardVisible = viewInsets > 0;

if (_keyboardWasVisible && !keyboardVisible) {
final int lastEventId = _keyboardClosedNotifier.value.eventId;
final newEventId = lastEventId + 1;
_keyboardClosedNotifier.value =
SoftKeyboardClosedEvent(eventId: newEventId);
}

_keyboardWasVisible = keyboardVisible;
}

/// Returns a ValueNotifier<SoftKeyboardClosedEvent> to provide access to the notifier
/// from the widget tree, allowing other widgets to listen and react to keyboard closure events.
ValueListenable<SoftKeyboardClosedEvent> get softKeyboardClosureListenable =>
_keyboardClosedNotifier;
}
1 change: 0 additions & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ environment:
dependencies:
flutter:
sdk: flutter
flutter_keyboard_visibility: ^6.0.0

flutter:
uses-material-design: true
Expand Down

0 comments on commit 8d4efac

Please sign in to comment.