diff --git a/lib/common/widgets/draggable_scrollable_sheet.dart b/lib/common/widgets/draggable_scrollable_sheet.dart index 597199e5..c3595b12 100644 --- a/lib/common/widgets/draggable_scrollable_sheet.dart +++ b/lib/common/widgets/draggable_scrollable_sheet.dart @@ -404,81 +404,6 @@ class DraggableScrollableSheet extends StatefulWidget { _DraggableScrollableSheetState(); } -/// A [Notification] related to the extent, which is the size, and scroll -/// offset, which is the position of the child list, of the -/// [DraggableScrollableSheet]. -/// -/// [DraggableScrollableSheet] widgets notify their ancestors when the size of -/// the sheet changes. When the extent of the sheet changes via a drag, -/// this notification bubbles up through the tree, which means a given -/// [NotificationListener] will receive notifications for all descendant -/// [DraggableScrollableSheet] widgets. To focus on notifications from the -/// nearest [DraggableScrollableSheet] descendant, check that the [depth] -/// property of the notification is zero. -/// -/// When an extent notification is received by a [NotificationListener], the -/// listener will already have completed build and layout, and it is therefore -/// too late for that widget to call [State.setState]. Any attempt to adjust the -/// build or layout based on an extent notification would result in a layout -/// that lagged one frame behind, which is a poor user experience. Extent -/// notifications are used primarily to drive animations. The [Scaffold] widget -/// listens for extent notifications and responds by driving animations for the -/// [FloatingActionButton] as the bottom sheet scrolls up. -class DraggableScrollableNotification extends Notification - with ViewportNotificationMixin { - /// Creates a notification that the extent of a [DraggableScrollableSheet] has - /// changed. - /// - /// All parameters are required. The [minExtent] must be >= 0. The [maxExtent] - /// must be <= 1.0. The [extent] must be between [minExtent] and [maxExtent]. - DraggableScrollableNotification({ - required this.extent, - required this.minExtent, - required this.maxExtent, - required this.initialExtent, - required this.context, - this.shouldCloseOnMinExtent = true, - }) : assert(0.0 <= minExtent), - assert(maxExtent <= 1.0), - assert(minExtent <= extent), - assert(minExtent <= initialExtent), - assert(extent <= maxExtent), - assert(initialExtent <= maxExtent); - - /// The current value of the extent, between [minExtent] and [maxExtent]. - final double extent; - - /// The minimum value of [extent], which is >= 0. - final double minExtent; - - /// The maximum value of [extent]. - final double maxExtent; - - /// The initially requested value for [extent]. - final double initialExtent; - - /// The build context of the widget that fired this notification. - /// - /// This can be used to find the sheet's render objects to determine the size - /// of the viewport, for instance. A listener can only assume this context - /// is live when it first gets the notification. - final BuildContext context; - - /// Whether the widget that fired this notification, when dragged (or flung) - /// to minExtent, should cause its parent sheet to close. - /// - /// It is up to parent classes to properly read and handle this value. - final bool shouldCloseOnMinExtent; - - @override - void debugFillDescription(List description) { - super.debugFillDescription(description); - description.add( - 'minExtent: $minExtent, extent: $extent, maxExtent: $maxExtent, initialExtent: $initialExtent', - ); - } -} - /// Manages state between [_DraggableScrollableSheetState], /// [_DraggableScrollableSheetScrollController], and /// [_DraggableScrollableSheetScrollPosition]. diff --git a/lib/pages/dynamics_create/view.dart b/lib/pages/dynamics_create/view.dart index 81e45d44..91132474 100644 --- a/lib/pages/dynamics_create/view.dart +++ b/lib/pages/dynamics_create/view.dart @@ -614,7 +614,7 @@ class _CreateDynPanelState extends CommonPublishPageState { maxChildSize: 1, initialChildSize: _offset == 0 ? 0.65 : 1, initialScrollOffset: _offset, - snapSizes: [0.65], + snapSizes: const [0.65], builder: (context, scrollController) => SelectTopicPanel( scrollController: scrollController, callback: (offset) => _offset = offset, diff --git a/lib/pages/dynamics_select_topic/controller.dart b/lib/pages/dynamics_select_topic/controller.dart index c7e67d8c..2293fcfb 100644 --- a/lib/pages/dynamics_select_topic/controller.dart +++ b/lib/pages/dynamics_select_topic/controller.dart @@ -8,6 +8,7 @@ import 'package:get/get.dart'; class SelectTopicController extends CommonListController { + final focusNode = FocusNode(); final controller = TextEditingController(); final RxBool enableClear = false.obs; @@ -32,6 +33,7 @@ class SelectTopicController @override void onClose() { + focusNode.dispose(); controller.dispose(); super.onClose(); } diff --git a/lib/pages/dynamics_select_topic/view.dart b/lib/pages/dynamics_select_topic/view.dart index 5cabf743..70535607 100644 --- a/lib/pages/dynamics_select_topic/view.dart +++ b/lib/pages/dynamics_select_topic/view.dart @@ -1,3 +1,5 @@ +import 'dart:async'; + import 'package:PiliPlus/common/widgets/custom_icon.dart'; import 'package:PiliPlus/common/widgets/loading_widget/loading_widget.dart'; import 'package:PiliPlus/http/loading_state.dart'; @@ -5,9 +7,9 @@ import 'package:PiliPlus/models/topic_pub_search/topic_item.dart'; import 'package:PiliPlus/pages/dynamics_select_topic/controller.dart'; import 'package:PiliPlus/utils/extension.dart'; import 'package:PiliPlus/utils/utils.dart'; -import 'package:easy_debounce/easy_throttle.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; +import 'package:stream_transform/stream_transform.dart'; class SelectTopicPanel extends StatefulWidget { const SelectTopicPanel({ @@ -25,8 +27,9 @@ class SelectTopicPanel extends StatefulWidget { class _SelectTopicPanelState extends State { final _controller = Get.put(SelectTopicController()); - - double offset = 0; + late double offset; + final StreamController _ctr = StreamController(); + late StreamSubscription _sub; @override void initState() { @@ -35,11 +38,21 @@ class _SelectTopicPanelState extends State { _controller.onReload(); } offset = widget.scrollController?.initialScrollOffset ?? 0; + _sub = _ctr.stream + .debounce(const Duration(milliseconds: 300), trailing: true) + .listen((value) { + _controller + ..enableClear.value = value.isNotEmpty + ..onRefresh().whenComplete(() => WidgetsBinding.instance + .addPostFrameCallback((_) => widget.scrollController?.jumpToTop())); + }); } @override void dispose() { widget.callback?.call(offset); + _sub.cancel(); + _ctr.close(); super.dispose(); } @@ -69,17 +82,9 @@ class _SelectTopicPanelState extends State { Padding( padding: const EdgeInsets.only(left: 16, right: 16, bottom: 5), child: TextField( + focusNode: _controller.focusNode, controller: _controller.controller, - onChanged: (value) { - EasyThrottle.throttle( - 'topicPubSearch', - const Duration(milliseconds: 300), - () => _controller - ..enableClear.value = value.isNotEmpty - ..onRefresh() - .whenComplete(() => widget.scrollController?.jumpToTop()), - ); - }, + onChanged: _ctr.add, decoration: InputDecoration( border: const OutlineInputBorder( gapPadding: 0, @@ -119,8 +124,10 @@ class _SelectTopicPanelState extends State { onTap: () => _controller ..enableClear.value = false ..controller.clear() - ..onRefresh().whenComplete( - () => widget.scrollController?.jumpToTop()), + ..onRefresh().whenComplete(() => WidgetsBinding + .instance + .addPostFrameCallback((_) => + widget.scrollController?.jumpToTop())), ), ) : const SizedBox.shrink(), @@ -148,6 +155,9 @@ class _SelectTopicPanelState extends State { response?.isNotEmpty == true ? NotificationListener( onNotification: (notification) { + if (_controller.focusNode.hasFocus) { + _controller.focusNode.unfocus(); + } offset = notification.metrics.pixels; return false; },