opt select topic

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
bggRGjQaUbCoE
2025-05-26 18:40:57 +08:00
parent 3edac65ae8
commit 8ce33736a0
3 changed files with 1316 additions and 62 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -3,6 +3,8 @@ import 'dart:math';
import 'package:PiliPlus/common/widgets/button/icon_button.dart'; import 'package:PiliPlus/common/widgets/button/icon_button.dart';
import 'package:PiliPlus/common/widgets/button/toolbar_icon_button.dart'; import 'package:PiliPlus/common/widgets/button/toolbar_icon_button.dart';
import 'package:PiliPlus/common/widgets/custom_icon.dart'; import 'package:PiliPlus/common/widgets/custom_icon.dart';
import 'package:PiliPlus/common/widgets/draggable_scrollable_sheet.dart'
show DraggableScrollableSheet;
import 'package:PiliPlus/common/widgets/pair.dart'; import 'package:PiliPlus/common/widgets/pair.dart';
import 'package:PiliPlus/http/dynamics.dart'; import 'package:PiliPlus/http/dynamics.dart';
import 'package:PiliPlus/models/common/publish_panel_type.dart'; import 'package:PiliPlus/models/common/publish_panel_type.dart';
@@ -15,7 +17,7 @@ import 'package:PiliPlus/pages/emote/controller.dart';
import 'package:PiliPlus/pages/emote/view.dart'; import 'package:PiliPlus/pages/emote/view.dart';
import 'package:PiliPlus/utils/request_utils.dart'; import 'package:PiliPlus/utils/request_utils.dart';
import 'package:PiliPlus/utils/storage.dart'; import 'package:PiliPlus/utils/storage.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart' hide DraggableScrollableSheet;
import 'package:flutter/services.dart' show LengthLimitingTextInputFormatter; import 'package:flutter/services.dart' show LengthLimitingTextInputFormatter;
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
@@ -596,6 +598,7 @@ class _CreateDynPanelState extends CommonPublishPageState<CreateDynPanel> {
} }
} }
double _offset = 0;
Future<void> _onSelectTopic() async { Future<void> _onSelectTopic() async {
TopicPubSearchItem? res = await showModalBottomSheet( TopicPubSearchItem? res = await showModalBottomSheet(
context: context, context: context,
@@ -609,10 +612,13 @@ class _CreateDynPanelState extends CommonPublishPageState<CreateDynPanel> {
snap: true, snap: true,
minChildSize: 0, minChildSize: 0,
maxChildSize: 1, maxChildSize: 1,
initialChildSize: 0.65, initialChildSize: _offset == 0 ? 0.65 : 1,
initialScrollOffset: _offset,
snapSizes: [0.65], snapSizes: [0.65],
builder: (context, scrollController) => builder: (context, scrollController) => SelectTopicPanel(
SelectTopicPanel(scrollController: scrollController), scrollController: scrollController,
callback: (offset) => _offset = offset,
),
), ),
); );
if (res != null) { if (res != null) {

View File

@@ -13,9 +13,11 @@ class SelectTopicPanel extends StatefulWidget {
const SelectTopicPanel({ const SelectTopicPanel({
super.key, super.key,
this.scrollController, this.scrollController,
this.callback,
}); });
final ScrollController? scrollController; final ScrollController? scrollController;
final ValueChanged<double>? callback;
@override @override
State<SelectTopicPanel> createState() => _SelectTopicPanelState(); State<SelectTopicPanel> createState() => _SelectTopicPanelState();
@@ -24,6 +26,8 @@ class SelectTopicPanel extends StatefulWidget {
class _SelectTopicPanelState extends State<SelectTopicPanel> { class _SelectTopicPanelState extends State<SelectTopicPanel> {
final _controller = Get.put(SelectTopicController()); final _controller = Get.put(SelectTopicController());
double offset = 0;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
@@ -32,17 +36,20 @@ class _SelectTopicPanelState extends State<SelectTopicPanel> {
} }
} }
@override
void dispose() {
widget.callback?.call(offset);
super.dispose();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final theme = Theme.of(context); final theme = Theme.of(context);
return Column( return Column(
children: [ children: [
InkWell( GestureDetector(
onTap: Get.back, onTap: Get.back,
borderRadius: const BorderRadius.only( behavior: HitTestBehavior.opaque,
topLeft: Radius.circular(18),
topRight: Radius.circular(18),
),
child: Container( child: Container(
height: 35, height: 35,
padding: const EdgeInsets.only(bottom: 2), padding: const EdgeInsets.only(bottom: 2),
@@ -76,9 +83,7 @@ class _SelectTopicPanelState extends State<SelectTopicPanel> {
border: const OutlineInputBorder( border: const OutlineInputBorder(
gapPadding: 0, gapPadding: 0,
borderSide: BorderSide.none, borderSide: BorderSide.none,
borderRadius: BorderRadius.all( borderRadius: BorderRadius.all(Radius.circular(25)),
Radius.circular(25),
),
), ),
isDense: true, isDense: true,
filled: true, filled: true,
@@ -140,61 +145,66 @@ class _SelectTopicPanelState extends State<SelectTopicPanel> {
Loading() => loadingWidget, Loading() => loadingWidget,
Success<List<TopicPubSearchItem>?>(:var response) => Success<List<TopicPubSearchItem>?>(:var response) =>
response?.isNotEmpty == true response?.isNotEmpty == true
? ListView.builder( ? NotificationListener<ScrollNotification>(
padding: EdgeInsets.only( onNotification: (notification) {
bottom: MediaQuery.paddingOf(context).bottom + offset = notification.metrics.pixels;
MediaQuery.viewInsetsOf(context).bottom + return false;
80, },
), child: ListView.builder(
controller: widget.scrollController, padding: EdgeInsets.only(
itemBuilder: (context, index) { bottom: MediaQuery.paddingOf(context).bottom +
if (index == response.length - 1) { MediaQuery.viewInsetsOf(context).bottom +
_controller.onLoadMore(); 80,
} ),
final item = response[index]; controller: widget.scrollController,
return ListTile( itemBuilder: (context, index) {
dense: true, if (index == response.length - 1) {
onTap: () => Get.back(result: item), _controller.onLoadMore();
title: Text.rich( }
TextSpan( final item = response[index];
children: [ return ListTile(
const WidgetSpan( dense: true,
alignment: PlaceholderAlignment.middle, onTap: () => Get.back(result: item),
child: Padding( title: Text.rich(
padding: EdgeInsets.only(right: 5), TextSpan(
child: Icon( children: [
CustomIcon.topic_tag, const WidgetSpan(
size: 18, alignment: PlaceholderAlignment.middle,
child: Padding(
padding: EdgeInsets.only(right: 5),
child: Icon(
CustomIcon.topic_tag,
size: 18,
),
), ),
), ),
), TextSpan(
TextSpan( text: item.name,
text: item.name, style: const TextStyle(fontSize: 14),
style: const TextStyle(fontSize: 14), ),
), ],
], ),
), ),
), subtitle: Padding(
subtitle: Padding( padding: const EdgeInsets.only(left: 23),
padding: const EdgeInsets.only(left: 23), child: Text(
child: Text( '${Utils.numFormat(item.view)}浏览 · ${Utils.numFormat(item.discuss)}讨论',
'${Utils.numFormat(item.view)}浏览 · ${Utils.numFormat(item.discuss)}讨论', style: TextStyle(color: theme.colorScheme.outline),
style: TextStyle(color: theme.colorScheme.outline), ),
), ),
), );
); },
}, itemCount: response!.length,
itemCount: response!.length, ),
) )
: scrollErrorWidget( : _errWidget(),
controller: widget.scrollController, Error(:var errMsg) => _errWidget(errMsg),
onReload: _controller.onReload,
),
Error(:var errMsg) => scrollErrorWidget(
errMsg: errMsg,
controller: widget.scrollController,
onReload: _controller.onReload,
),
}; };
} }
Widget _errWidget([String? errMsg]) => scrollErrorWidget(
errMsg: errMsg,
controller: widget.scrollController,
onReload: _controller.onReload,
);
} }