opt: select (#937)

This commit is contained in:
My-Responsitories
2025-08-05 13:41:37 +08:00
committed by GitHub
parent afb09e8a0a
commit 01552801f2
20 changed files with 425 additions and 595 deletions

View File

@@ -1,6 +1,8 @@
import 'package:PiliPlus/common/widgets/appbar/appbar.dart';
import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart';
import 'package:PiliPlus/http/loading_state.dart';
import 'package:PiliPlus/pages/common/common_search_controller.dart';
import 'package:PiliPlus/pages/common/multi_select_controller.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
@@ -12,43 +14,33 @@ abstract class CommonSearchPageState<S extends CommonSearchPage, R, T>
extends State<S> {
CommonSearchController<R, T> get controller;
List<Widget>? extraActions;
List<Widget>? get extraActions => null;
List<Widget>? get multiSelectChildren => null;
@override
Widget build(BuildContext context) {
if (controller case MultiSelectBase multiCtr) {
return Obx(() {
final enableMultiSelect = multiCtr.enableMultiSelect.value;
return PopScope(
canPop: !enableMultiSelect,
onPopInvokedWithResult: (didPop, result) {
if (enableMultiSelect) {
multiCtr.handleSelect();
}
},
child: _build(true),
);
});
}
return _build(false);
}
Widget _build(bool multiSelect) {
return Scaffold(
resizeToAvoidBottomInset: false,
appBar: AppBar(
actions: [
IconButton(
tooltip: '搜索',
onPressed: controller.onRefresh,
icon: const Icon(Icons.search_outlined, size: 22),
),
...?extraActions,
const SizedBox(width: 10),
],
title: TextField(
autofocus: true,
focusNode: controller.focusNode,
controller: controller.editController,
textInputAction: TextInputAction.search,
textAlignVertical: TextAlignVertical.center,
decoration: InputDecoration(
hintText: '搜索',
border: InputBorder.none,
suffixIcon: IconButton(
tooltip: '清空',
icon: const Icon(Icons.clear, size: 22),
onPressed: () => controller
..loadingState.value = LoadingState.loading()
..onClear()
..focusNode.requestFocus(),
),
),
onSubmitted: (value) => controller.onRefresh(),
),
),
appBar: _buildBar(multiSelect),
body: SafeArea(
top: false,
bottom: false,
@@ -68,6 +60,48 @@ abstract class CommonSearchPageState<S extends CommonSearchPage, R, T>
);
}
PreferredSizeWidget _buildBar(bool multiSelect) {
final AppBar bar = AppBar(
actions: [
IconButton(
tooltip: '搜索',
onPressed: controller.onRefresh,
icon: const Icon(Icons.search_outlined, size: 22),
),
...?extraActions,
const SizedBox(width: 10),
],
title: TextField(
autofocus: true,
focusNode: controller.focusNode,
controller: controller.editController,
textInputAction: TextInputAction.search,
textAlignVertical: TextAlignVertical.center,
decoration: InputDecoration(
hintText: '搜索',
border: InputBorder.none,
suffixIcon: IconButton(
tooltip: '清空',
icon: const Icon(Icons.clear, size: 22),
onPressed: () => controller
..loadingState.value = LoadingState.loading()
..onClear()
..focusNode.requestFocus(),
),
),
onSubmitted: (value) => controller.onRefresh(),
),
);
if (multiSelect) {
return MultiSelectAppBarWidget(
ctr: controller as MultiSelectBase,
children: multiSelectChildren,
child: bar,
);
}
return bar;
}
Widget _buildBody(LoadingState<List<T>?> loadingState) {
return switch (loadingState) {
Loading() => const HttpError(),