From 7854c5e6b9191616f5b2ed968858be996d7a9225 Mon Sep 17 00:00:00 2001 From: My-Responsitories <107370289+My-Responsitories@users.noreply.github.com> Date: Sun, 16 Mar 2025 13:34:04 +0800 Subject: [PATCH] split report dialog (#460) --- lib/common/widgets/radio_widget.dart | 99 ++++++-- lib/common/widgets/report.dart | 324 +++++++++++++-------------- lib/pages/member/view.dart | 2 +- lib/utils/utils.dart | 2 +- 4 files changed, 242 insertions(+), 185 deletions(-) diff --git a/lib/common/widgets/radio_widget.dart b/lib/common/widgets/radio_widget.dart index fa8c26d1..b4a22c8c 100644 --- a/lib/common/widgets/radio_widget.dart +++ b/lib/common/widgets/radio_widget.dart @@ -1,15 +1,24 @@ import 'package:flutter/material.dart'; -Widget radioWidget({ - required T value, - T? groupValue, - required ValueChanged onChanged, - required String title, - EdgeInsetsGeometry? padding, -}) { - Widget child() => Row( +class RadioWidget extends StatelessWidget { + final T value; + final T? groupValue; + final ValueChanged onChanged; + final String title; + final EdgeInsetsGeometry? padding; + + const RadioWidget({ + super.key, + required this.value, + this.groupValue, + required this.onChanged, + required this.title, + this.padding, + }); + + Widget _child() => Row( children: [ - Radio( + Radio( value: value, groupValue: groupValue, onChanged: onChanged, @@ -18,13 +27,67 @@ Widget radioWidget({ Text(title), ], ); - return InkWell( - onTap: () => onChanged(value), - child: padding != null - ? Padding( - padding: padding, - child: child(), - ) - : child(), - ); + + @override + Widget build(BuildContext context) { + return InkWell( + onTap: () => onChanged(value), + child: padding != null + ? Padding( + padding: padding!, + child: _child(), + ) + : _child(), + ); + } +} + +class WrapRadioOptionsGroup extends StatelessWidget { + final String groupTitle; + final Map options; + final T? selectedValue; + final ValueChanged onChanged; + final EdgeInsetsGeometry? itemPadding; + + const WrapRadioOptionsGroup({ + super.key, + required this.groupTitle, + required this.options, + required this.selectedValue, + required this.onChanged, + this.itemPadding, + }); + + @override + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (groupTitle.isNotEmpty) + Padding( + padding: const EdgeInsets.only(left: 22), + child: Text( + groupTitle, + style: TextStyle(color: Theme.of(context).colorScheme.outline), + ), + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 12), + child: Wrap( + children: options.entries.map((entry) { + return IntrinsicWidth( + child: RadioWidget( + value: entry.key, + groupValue: selectedValue, + onChanged: onChanged, + title: entry.value, + padding: itemPadding ?? const EdgeInsets.only(right: 10), + ), + ); + }).toList(), + ), + ), + ], + ); + } } diff --git a/lib/common/widgets/report.dart b/lib/common/widgets/report.dart index b7a43147..9dcb139c 100644 --- a/lib/common/widgets/report.dart +++ b/lib/common/widgets/report.dart @@ -1,7 +1,6 @@ import 'package:PiliPlus/common/widgets/radio_widget.dart'; import 'package:PiliPlus/utils/extension.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; @@ -16,186 +15,181 @@ void autoWrapReportDialog( late final key = GlobalKey(); showDialog( context: context, - builder: (context) { - return AlertDialog( - title: const Text('举报'), - titlePadding: const EdgeInsets.only(left: 22, top: 16, right: 22), - contentPadding: const EdgeInsets.symmetric(vertical: 5), - actionsPadding: const EdgeInsets.only(left: 16, right: 16, bottom: 10), - content: Builder( - builder: (context) { - return Column( + builder: (context) => StatefulBuilder( + builder: (context, setState) { + return AlertDialog( + title: const Text('举报'), + titlePadding: const EdgeInsets.only(left: 22, top: 16, right: 22), + contentPadding: const EdgeInsets.symmetric(vertical: 5), + actionsPadding: + const EdgeInsets.only(left: 16, right: 16, bottom: 10), + content: Form( + key: key, + child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Flexible( - child: Material( - child: SingleChildScrollView( - child: AnimatedSize( - duration: const Duration(milliseconds: 200), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.only( - left: 22, - right: 22, - bottom: 5, - ), - child: const Text('请选择举报的理由:'), + child: SingleChildScrollView( + child: AnimatedSize( + duration: const Duration(milliseconds: 200), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Padding( + padding: EdgeInsets.only( + left: 22, + right: 22, + bottom: 5, ), - ...options.entries.map((title) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - if (title.key.isNotEmpty) - Padding( - padding: const EdgeInsets.only(left: 22), - child: Text( - title.key, - style: TextStyle( - color: Theme.of(context) - .colorScheme - .outline), - ), - ), - Padding( - padding: const EdgeInsets.symmetric( - horizontal: 12), - child: Wrap( - children: title.value.entries.map((opt) { - return IntrinsicWidth( - child: radioWidget( - value: opt.key, - groupValue: reasonType, - title: opt.value, - padding: const EdgeInsets.only( - right: 10), - onChanged: (value) { - reasonType = value; - if (context.mounted) { - (context as Element?) - ?.markNeedsBuild(); - } - }, - ), - ); - }).toList(), - ), - ), - ], - ); - }), - if (reasonType == 0) - Padding( - padding: const EdgeInsets.only( - left: 22, - top: 5, - right: 22, - ), - child: Form( - key: key, - child: TextFormField( - autofocus: true, - minLines: 4, - maxLines: 4, - initialValue: reasonDesc, - inputFormatters: [ - LengthLimitingTextInputFormatter(60), - ], - decoration: const InputDecoration( - labelText: - '为帮助审核人员更快处理,请补充问题类型和出现位置等详细信息', - border: OutlineInputBorder(), - contentPadding: EdgeInsets.all(10), - ), - onChanged: (value) => reasonDesc = value, - validator: (value) { - if (value.isNullOrEmpty) { - return '理由不能为空'; - } - return null; - }, - ), - ), - ), - ], - ), + child: Text('请选择举报的理由:'), + ), + ...options.entries.map( + (entry) => WrapRadioOptionsGroup( + groupTitle: entry.key, + options: entry.value, + selectedValue: reasonType, + onChanged: (value) => + setState(() => reasonType = value), + ), + ), + if (reasonType == 0) + ReasonField( + onChanged: (value) => reasonDesc = value), + ], ), ), ), ), - GestureDetector( - onTap: () { - banUid = !banUid; - (context as Element?)?.markNeedsBuild(); - }, - child: Padding( - padding: const EdgeInsets.only(left: 18, top: 10), - child: Row( - children: [ - Icon( - size: 22, - banUid - ? Icons.check_box_outlined - : Icons.check_box_outline_blank, - color: banUid - ? Theme.of(context).colorScheme.primary - : Theme.of(context).colorScheme.onSurfaceVariant, - ), - Text( - ' 拉黑该用户', - style: TextStyle( - color: banUid - ? Theme.of(context).colorScheme.primary - : null, - ), - ), - ], - ), - ), - ), + BanUserCheckbox(onChanged: (value) => banUid = value), ], - ); - }, - ), - actions: [ - TextButton( - onPressed: Get.back, - child: Text( - '取消', - style: TextStyle(color: Theme.of(context).colorScheme.outline), ), ), - TextButton( - onPressed: () async { - if (reasonType == null || - (reasonType == 0 && key.currentState?.validate() != true)) { - return; - } - SmartDialog.showLoading(); - try { - final data = await onSuccess(reasonType!, reasonDesc, banUid); - SmartDialog.dismiss(); - if (data['code'] == 0) { - Get.back(); - SmartDialog.showToast('举报成功'); - } else { - SmartDialog.showToast(data['message']); + actions: [ + TextButton( + onPressed: Get.back, + child: Text( + '取消', + style: TextStyle(color: Theme.of(context).colorScheme.outline), + ), + ), + TextButton( + onPressed: () async { + if (reasonType == null || + (reasonType == 0 && key.currentState?.validate() != true)) { + return; } - } catch (e) { - SmartDialog.dismiss(); - SmartDialog.showToast('提交失败:$e'); - } - }, - child: const Text('确定'), - ), - ], - ); - }, + SmartDialog.showLoading(); + try { + final data = await onSuccess(reasonType!, reasonDesc, banUid); + SmartDialog.dismiss(); + if (data['code'] == 0) { + Get.back(); + SmartDialog.showToast('举报成功'); + } else { + SmartDialog.showToast(data['message']); + } + } catch (e) { + SmartDialog.dismiss(); + SmartDialog.showToast('提交失败:$e'); + } + }, + child: const Text('确定'), + ), + ], + ); + }, + ), ); } +class ReasonField extends StatefulWidget { + final ValueChanged onChanged; + String? _validator(String? value) => value.isNullOrEmpty ? '理由不能为空' : null; + + const ReasonField({super.key, required this.onChanged}); + + @override + State createState() => _ReasonFieldState(); +} + +class _ReasonFieldState extends State { + final _controller = TextEditingController(); + + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.only(left: 22, top: 5, right: 22), + child: TextFormField( + controller: _controller, + autofocus: true, + minLines: 4, + maxLines: 4, + decoration: const InputDecoration( + labelText: '为帮助审核人员更快处理,请补充问题类型和出现位置等详细信息', + border: OutlineInputBorder(), + contentPadding: EdgeInsets.all(10), + ), + onChanged: (value) { + widget.onChanged(value); + }, + validator: widget._validator, + ), + ); + } +} + +class BanUserCheckbox extends StatefulWidget { + final ValueChanged onChanged; + + const BanUserCheckbox({super.key, required this.onChanged}); + + @override + State createState() => _BanUserCheckboxState(); +} + +class _BanUserCheckboxState extends State { + bool _banUid = false; + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: () { + setState(() => _banUid = !_banUid); + widget.onChanged(_banUid); + }, + child: Padding( + padding: const EdgeInsets.only(left: 18, top: 10), + child: Row( + children: [ + Icon( + size: 22, + _banUid + ? Icons.check_box_outlined + : Icons.check_box_outline_blank, + color: _banUid + ? Theme.of(context).colorScheme.primary + : Theme.of(context).colorScheme.onSurfaceVariant, + ), + Text( + ' 拉黑该用户', + style: TextStyle( + color: _banUid ? Theme.of(context).colorScheme.primary : null, + ), + ), + ], + ), + ), + ); + } +} + class ReportOptions { // from https://s1.hdslb.com/bfs/seed/jinkela/comment-h5/static/js/605.chunks.js static Map> get commentReport => { diff --git a/lib/pages/member/view.dart b/lib/pages/member/view.dart index 7b857150..2ab6711d 100644 --- a/lib/pages/member/view.dart +++ b/lib/pages/member/view.dart @@ -582,7 +582,7 @@ class _ReportPanelState extends State { const Text('举报理由(单选,非必选)'), ...List.generate( 5, - (index) => radioWidget( + (index) => RadioWidget( value: index, groupValue: _reasonV2, onChanged: (value) { diff --git a/lib/utils/utils.dart b/lib/utils/utils.dart index 17bbbc75..142a714c 100644 --- a/lib/utils/utils.dart +++ b/lib/utils/utils.dart @@ -407,7 +407,7 @@ class Utils { child: Builder( builder: (context) => Column( children: List.generate(list.length, (index) { - return radioWidget( + return RadioWidget( padding: const EdgeInsets.only(left: 14), title: list[index].title ?? '', groupValue: checkedId,