mirror of
https://github.com/bggRGjQaUbCoE/PiliPlus.git
synced 2026-05-30 23:58:13 +08:00
opt search topic
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
@@ -404,81 +404,6 @@ class DraggableScrollableSheet extends StatefulWidget {
|
|||||||
_DraggableScrollableSheetState();
|
_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],
|
/// Manages state between [_DraggableScrollableSheetState],
|
||||||
/// [_DraggableScrollableSheetScrollController], and
|
/// [_DraggableScrollableSheetScrollController], and
|
||||||
/// [_DraggableScrollableSheetScrollPosition].
|
/// [_DraggableScrollableSheetScrollPosition].
|
||||||
|
|||||||
@@ -614,7 +614,7 @@ class _CreateDynPanelState extends CommonPublishPageState<CreateDynPanel> {
|
|||||||
maxChildSize: 1,
|
maxChildSize: 1,
|
||||||
initialChildSize: _offset == 0 ? 0.65 : 1,
|
initialChildSize: _offset == 0 ? 0.65 : 1,
|
||||||
initialScrollOffset: _offset,
|
initialScrollOffset: _offset,
|
||||||
snapSizes: [0.65],
|
snapSizes: const [0.65],
|
||||||
builder: (context, scrollController) => SelectTopicPanel(
|
builder: (context, scrollController) => SelectTopicPanel(
|
||||||
scrollController: scrollController,
|
scrollController: scrollController,
|
||||||
callback: (offset) => _offset = offset,
|
callback: (offset) => _offset = offset,
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import 'package:get/get.dart';
|
|||||||
|
|
||||||
class SelectTopicController
|
class SelectTopicController
|
||||||
extends CommonListController<TopicPubSearchData, TopicPubSearchItem> {
|
extends CommonListController<TopicPubSearchData, TopicPubSearchItem> {
|
||||||
|
final focusNode = FocusNode();
|
||||||
final controller = TextEditingController();
|
final controller = TextEditingController();
|
||||||
|
|
||||||
final RxBool enableClear = false.obs;
|
final RxBool enableClear = false.obs;
|
||||||
@@ -32,6 +33,7 @@ class SelectTopicController
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
void onClose() {
|
void onClose() {
|
||||||
|
focusNode.dispose();
|
||||||
controller.dispose();
|
controller.dispose();
|
||||||
super.onClose();
|
super.onClose();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:PiliPlus/common/widgets/custom_icon.dart';
|
import 'package:PiliPlus/common/widgets/custom_icon.dart';
|
||||||
import 'package:PiliPlus/common/widgets/loading_widget/loading_widget.dart';
|
import 'package:PiliPlus/common/widgets/loading_widget/loading_widget.dart';
|
||||||
import 'package:PiliPlus/http/loading_state.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/pages/dynamics_select_topic/controller.dart';
|
||||||
import 'package:PiliPlus/utils/extension.dart';
|
import 'package:PiliPlus/utils/extension.dart';
|
||||||
import 'package:PiliPlus/utils/utils.dart';
|
import 'package:PiliPlus/utils/utils.dart';
|
||||||
import 'package:easy_debounce/easy_throttle.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
import 'package:stream_transform/stream_transform.dart';
|
||||||
|
|
||||||
class SelectTopicPanel extends StatefulWidget {
|
class SelectTopicPanel extends StatefulWidget {
|
||||||
const SelectTopicPanel({
|
const SelectTopicPanel({
|
||||||
@@ -25,8 +27,9 @@ class SelectTopicPanel extends StatefulWidget {
|
|||||||
|
|
||||||
class _SelectTopicPanelState extends State<SelectTopicPanel> {
|
class _SelectTopicPanelState extends State<SelectTopicPanel> {
|
||||||
final _controller = Get.put(SelectTopicController());
|
final _controller = Get.put(SelectTopicController());
|
||||||
|
late double offset;
|
||||||
double offset = 0;
|
final StreamController<String> _ctr = StreamController<String>();
|
||||||
|
late StreamSubscription<String> _sub;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
@@ -35,11 +38,21 @@ class _SelectTopicPanelState extends State<SelectTopicPanel> {
|
|||||||
_controller.onReload();
|
_controller.onReload();
|
||||||
}
|
}
|
||||||
offset = widget.scrollController?.initialScrollOffset ?? 0;
|
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
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
widget.callback?.call(offset);
|
widget.callback?.call(offset);
|
||||||
|
_sub.cancel();
|
||||||
|
_ctr.close();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,17 +82,9 @@ class _SelectTopicPanelState extends State<SelectTopicPanel> {
|
|||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.only(left: 16, right: 16, bottom: 5),
|
padding: const EdgeInsets.only(left: 16, right: 16, bottom: 5),
|
||||||
child: TextField(
|
child: TextField(
|
||||||
|
focusNode: _controller.focusNode,
|
||||||
controller: _controller.controller,
|
controller: _controller.controller,
|
||||||
onChanged: (value) {
|
onChanged: _ctr.add,
|
||||||
EasyThrottle.throttle(
|
|
||||||
'topicPubSearch',
|
|
||||||
const Duration(milliseconds: 300),
|
|
||||||
() => _controller
|
|
||||||
..enableClear.value = value.isNotEmpty
|
|
||||||
..onRefresh()
|
|
||||||
.whenComplete(() => widget.scrollController?.jumpToTop()),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
border: const OutlineInputBorder(
|
border: const OutlineInputBorder(
|
||||||
gapPadding: 0,
|
gapPadding: 0,
|
||||||
@@ -119,8 +124,10 @@ class _SelectTopicPanelState extends State<SelectTopicPanel> {
|
|||||||
onTap: () => _controller
|
onTap: () => _controller
|
||||||
..enableClear.value = false
|
..enableClear.value = false
|
||||||
..controller.clear()
|
..controller.clear()
|
||||||
..onRefresh().whenComplete(
|
..onRefresh().whenComplete(() => WidgetsBinding
|
||||||
() => widget.scrollController?.jumpToTop()),
|
.instance
|
||||||
|
.addPostFrameCallback((_) =>
|
||||||
|
widget.scrollController?.jumpToTop())),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
: const SizedBox.shrink(),
|
: const SizedBox.shrink(),
|
||||||
@@ -148,6 +155,9 @@ class _SelectTopicPanelState extends State<SelectTopicPanel> {
|
|||||||
response?.isNotEmpty == true
|
response?.isNotEmpty == true
|
||||||
? NotificationListener<ScrollNotification>(
|
? NotificationListener<ScrollNotification>(
|
||||||
onNotification: (notification) {
|
onNotification: (notification) {
|
||||||
|
if (_controller.focusNode.hasFocus) {
|
||||||
|
_controller.focusNode.unfocus();
|
||||||
|
}
|
||||||
offset = notification.metrics.pixels;
|
offset = notification.metrics.pixels;
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user