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