mirror of
https://github.com/HChaZZY/PiliPlus.git
synced 2025-12-06 09:13:48 +08:00
@@ -10,11 +10,11 @@ import 'package:PiliPlus/http/loading_state.dart';
|
||||
import 'package:PiliPlus/models_new/dynamic/dyn_mention/group.dart';
|
||||
import 'package:PiliPlus/pages/dynamics_mention/controller.dart';
|
||||
import 'package:PiliPlus/pages/dynamics_mention/widgets/item.dart';
|
||||
import 'package:PiliPlus/pages/search/controller.dart';
|
||||
import 'package:PiliPlus/utils/context_ext.dart';
|
||||
import 'package:PiliPlus/utils/extension.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart' hide ContextExtensionss;
|
||||
import 'package:stream_transform/stream_transform.dart';
|
||||
|
||||
class DynMentionPanel extends StatefulWidget {
|
||||
const DynMentionPanel({
|
||||
@@ -58,10 +58,11 @@ class DynMentionPanel extends StatefulWidget {
|
||||
State<DynMentionPanel> createState() => _DynMentionPanelState();
|
||||
}
|
||||
|
||||
class _DynMentionPanelState extends State<DynMentionPanel> {
|
||||
class _DynMentionPanelState extends State<DynMentionPanel>
|
||||
with SearchKeywordMixin {
|
||||
final _controller = Get.put(DynMentionController());
|
||||
final StreamController<String> _ctr = StreamController<String>();
|
||||
late StreamSubscription<String> _sub;
|
||||
@override
|
||||
Duration get duration => const Duration(milliseconds: 300);
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@@ -69,25 +70,24 @@ class _DynMentionPanelState extends State<DynMentionPanel> {
|
||||
if (_controller.loadingState.value is Error) {
|
||||
_controller.onReload();
|
||||
}
|
||||
_sub = _ctr.stream
|
||||
.debounce(const Duration(milliseconds: 300), trailing: true)
|
||||
.listen((value) {
|
||||
_controller
|
||||
subInit();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
subDispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
ValueChanged<String> get onKeywordChanged =>
|
||||
(value) => _controller
|
||||
..enableClear.value = value.isNotEmpty
|
||||
..onRefresh().whenComplete(
|
||||
() => WidgetsBinding.instance.addPostFrameCallback(
|
||||
(_) => widget.scrollController?.jumpToTop(),
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_sub.cancel();
|
||||
_ctr.close();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -114,7 +114,7 @@ class _DynMentionPanelState extends State<DynMentionPanel> {
|
||||
child: TextField(
|
||||
focusNode: _controller.focusNode,
|
||||
controller: _controller.controller,
|
||||
onChanged: _ctr.add,
|
||||
onChanged: ctr!.add,
|
||||
decoration: InputDecoration(
|
||||
border: const OutlineInputBorder(
|
||||
gapPadding: 0,
|
||||
|
||||
@@ -8,11 +8,11 @@ import 'package:PiliPlus/http/loading_state.dart';
|
||||
import 'package:PiliPlus/models_new/dynamic/dyn_topic_top/topic_item.dart';
|
||||
import 'package:PiliPlus/pages/dynamics_select_topic/controller.dart';
|
||||
import 'package:PiliPlus/pages/dynamics_select_topic/widgets/item.dart';
|
||||
import 'package:PiliPlus/pages/search/controller.dart';
|
||||
import 'package:PiliPlus/utils/context_ext.dart';
|
||||
import 'package:PiliPlus/utils/extension.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart' hide ContextExtensionss;
|
||||
import 'package:stream_transform/stream_transform.dart';
|
||||
|
||||
class SelectTopicPanel extends StatefulWidget {
|
||||
const SelectTopicPanel({
|
||||
@@ -56,10 +56,11 @@ class SelectTopicPanel extends StatefulWidget {
|
||||
State<SelectTopicPanel> createState() => _SelectTopicPanelState();
|
||||
}
|
||||
|
||||
class _SelectTopicPanelState extends State<SelectTopicPanel> {
|
||||
class _SelectTopicPanelState extends State<SelectTopicPanel>
|
||||
with SearchKeywordMixin {
|
||||
final _controller = Get.put(SelectTopicController());
|
||||
final StreamController<String> _ctr = StreamController<String>();
|
||||
late StreamSubscription<String> _sub;
|
||||
@override
|
||||
Duration get duration => const Duration(milliseconds: 300);
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@@ -67,25 +68,24 @@ class _SelectTopicPanelState extends State<SelectTopicPanel> {
|
||||
if (_controller.loadingState.value is Error) {
|
||||
_controller.onReload();
|
||||
}
|
||||
_sub = _ctr.stream
|
||||
.debounce(const Duration(milliseconds: 300), trailing: true)
|
||||
.listen((value) {
|
||||
_controller
|
||||
subInit();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
subDispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
ValueChanged<String> get onKeywordChanged =>
|
||||
(value) => _controller
|
||||
..enableClear.value = value.isNotEmpty
|
||||
..onRefresh().whenComplete(
|
||||
() => WidgetsBinding.instance.addPostFrameCallback(
|
||||
(_) => widget.scrollController?.jumpToTop(),
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_sub.cancel();
|
||||
_ctr.close();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -110,7 +110,7 @@ class _SelectTopicPanelState extends State<SelectTopicPanel> {
|
||||
child: TextField(
|
||||
focusNode: _controller.focusNode,
|
||||
controller: _controller.controller,
|
||||
onChanged: _ctr.add,
|
||||
onChanged: ctr!.add,
|
||||
decoration: InputDecoration(
|
||||
border: const OutlineInputBorder(
|
||||
gapPadding: 0,
|
||||
|
||||
@@ -14,7 +14,26 @@ import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:stream_transform/stream_transform.dart';
|
||||
|
||||
class SSearchController extends GetxController {
|
||||
mixin SearchKeywordMixin {
|
||||
Duration duration = const Duration(milliseconds: 200);
|
||||
StreamController<String>? ctr;
|
||||
StreamSubscription<String>? sub;
|
||||
ValueChanged<String> get onKeywordChanged;
|
||||
|
||||
void subInit() {
|
||||
ctr = StreamController<String>();
|
||||
sub = ctr!.stream
|
||||
.debounce(duration, trailing: true)
|
||||
.listen(onKeywordChanged);
|
||||
}
|
||||
|
||||
void subDispose() {
|
||||
sub?.cancel();
|
||||
ctr?.close();
|
||||
}
|
||||
}
|
||||
|
||||
class SSearchController extends GetxController with SearchKeywordMixin {
|
||||
SSearchController(this.tag);
|
||||
final String tag;
|
||||
|
||||
@@ -34,8 +53,7 @@ class SSearchController extends GetxController {
|
||||
|
||||
// suggestion
|
||||
final bool searchSuggestion = Pref.searchSuggestion;
|
||||
StreamController<String>? _ctr;
|
||||
StreamSubscription<String>? _sub;
|
||||
|
||||
late final RxList<SearchSuggestItem> searchSuggestList;
|
||||
|
||||
// trending
|
||||
@@ -61,10 +79,7 @@ class SSearchController extends GetxController {
|
||||
).obs;
|
||||
|
||||
if (searchSuggestion) {
|
||||
_ctr = StreamController<String>();
|
||||
_sub = _ctr!.stream
|
||||
.debounce(const Duration(milliseconds: 200), trailing: true)
|
||||
.listen(querySearchSuggest);
|
||||
subInit();
|
||||
searchSuggestList = <SearchSuggestItem>[].obs;
|
||||
}
|
||||
|
||||
@@ -89,7 +104,7 @@ class SSearchController extends GetxController {
|
||||
if (value.isEmpty) {
|
||||
searchSuggestList.clear();
|
||||
} else {
|
||||
_ctr!.add(value);
|
||||
ctr!.add(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -154,7 +169,8 @@ class SSearchController extends GetxController {
|
||||
submit();
|
||||
}
|
||||
|
||||
Future<void> querySearchSuggest(String value) async {
|
||||
@override
|
||||
ValueChanged<String> get onKeywordChanged => (String value) async {
|
||||
var res = await SearchHttp.searchSuggest(term: value);
|
||||
if (res['status']) {
|
||||
SearchSuggestModel data = res['data'];
|
||||
@@ -162,7 +178,7 @@ class SSearchController extends GetxController {
|
||||
searchSuggestList.value = data.tag!;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void onLongSelect(String word) {
|
||||
historyList.remove(word);
|
||||
@@ -182,10 +198,9 @@ class SSearchController extends GetxController {
|
||||
|
||||
@override
|
||||
void onClose() {
|
||||
subDispose();
|
||||
searchFocusNode.dispose();
|
||||
controller.dispose();
|
||||
_sub?.cancel();
|
||||
_ctr?.close();
|
||||
super.onClose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart';
|
||||
import 'package:PiliPlus/pages/search/controller.dart';
|
||||
import 'package:PiliPlus/pages/setting/models/extra_settings.dart';
|
||||
import 'package:PiliPlus/pages/setting/models/model.dart';
|
||||
import 'package:PiliPlus/pages/setting/models/play_settings.dart';
|
||||
@@ -11,7 +10,6 @@ import 'package:PiliPlus/pages/setting/models/video_settings.dart';
|
||||
import 'package:PiliPlus/utils/grid.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:stream_transform/stream_transform.dart';
|
||||
import 'package:waterfall_flow/waterfall_flow.dart';
|
||||
|
||||
class SettingsSearchPage extends StatefulWidget {
|
||||
@@ -21,7 +19,8 @@ class SettingsSearchPage extends StatefulWidget {
|
||||
State<SettingsSearchPage> createState() => _SettingsSearchPageState();
|
||||
}
|
||||
|
||||
class _SettingsSearchPageState extends State<SettingsSearchPage> {
|
||||
class _SettingsSearchPageState extends State<SettingsSearchPage>
|
||||
with SearchKeywordMixin {
|
||||
final _textEditingController = TextEditingController();
|
||||
final RxList<SettingsModel> _list = <SettingsModel>[].obs;
|
||||
late final _settings = [
|
||||
@@ -32,16 +31,15 @@ class _SettingsSearchPageState extends State<SettingsSearchPage> {
|
||||
...playSettings,
|
||||
...styleSettings,
|
||||
];
|
||||
late StreamController<String> _ctr;
|
||||
late StreamSubscription<String> _sub;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_ctr = StreamController<String>();
|
||||
_sub = _ctr.stream
|
||||
.debounce(const Duration(milliseconds: 200), trailing: true)
|
||||
.listen((value) {
|
||||
subInit();
|
||||
}
|
||||
|
||||
@override
|
||||
ValueChanged<String> get onKeywordChanged => (value) {
|
||||
if (value.isEmpty) {
|
||||
_list.clear();
|
||||
} else {
|
||||
@@ -49,20 +47,18 @@ class _SettingsSearchPageState extends State<SettingsSearchPage> {
|
||||
_list.value = _settings
|
||||
.where(
|
||||
(item) =>
|
||||
(item.title ?? item.getTitle?.call())
|
||||
?.toLowerCase()
|
||||
.contains(value) ||
|
||||
(item.title ?? item.getTitle?.call())?.toLowerCase().contains(
|
||||
value,
|
||||
) ||
|
||||
item.subtitle?.toLowerCase().contains(value) == true,
|
||||
)
|
||||
.toList();
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_sub.cancel();
|
||||
_ctr.close();
|
||||
subDispose();
|
||||
_textEditingController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
@@ -89,7 +85,7 @@ class _SettingsSearchPageState extends State<SettingsSearchPage> {
|
||||
autofocus: true,
|
||||
controller: _textEditingController,
|
||||
textAlignVertical: TextAlignVertical.center,
|
||||
onChanged: _ctr.add,
|
||||
onChanged: ctr!.add,
|
||||
decoration: const InputDecoration(
|
||||
isDense: true,
|
||||
hintText: '搜索',
|
||||
|
||||
Reference in New Issue
Block a user