opt search topic

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
bggRGjQaUbCoE
2025-05-26 21:05:04 +08:00
parent 83de915e54
commit dbcc19cac1
4 changed files with 28 additions and 91 deletions

View File

@@ -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<String> description) {
super.debugFillDescription(description);
description.add(
'minExtent: $minExtent, extent: $extent, maxExtent: $maxExtent, initialExtent: $initialExtent',
);
}
}
/// Manages state between [_DraggableScrollableSheetState],
/// [_DraggableScrollableSheetScrollController], and
/// [_DraggableScrollableSheetScrollPosition].

View File

@@ -614,7 +614,7 @@ class _CreateDynPanelState extends CommonPublishPageState<CreateDynPanel> {
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,

View File

@@ -8,6 +8,7 @@ import 'package:get/get.dart';
class SelectTopicController
extends CommonListController<TopicPubSearchData, TopicPubSearchItem> {
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();
}

View File

@@ -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<SelectTopicPanel> {
final _controller = Get.put(SelectTopicController());
double offset = 0;
late double offset;
final StreamController<String> _ctr = StreamController<String>();
late StreamSubscription<String> _sub;
@override
void initState() {
@@ -35,11 +38,21 @@ class _SelectTopicPanelState extends State<SelectTopicPanel> {
_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<SelectTopicPanel> {
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<SelectTopicPanel> {
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<SelectTopicPanel> {
response?.isNotEmpty == true
? NotificationListener<ScrollNotification>(
onNotification: (notification) {
if (_controller.focusNode.hasFocus) {
_controller.focusNode.unfocus();
}
offset = notification.metrics.pixels;
return false;
},