diff --git a/lib/customWidget/custom_alert_dialog_two.dart b/lib/customWidget/custom_alert_dialog_two.dart new file mode 100644 index 0000000..36e54e4 --- /dev/null +++ b/lib/customWidget/custom_alert_dialog_two.dart @@ -0,0 +1,306 @@ +// custom_alert_dialog.dart +import 'package:flutter/material.dart'; +import 'package:qhd_prevention/customWidget/toast_util.dart'; +import 'package:qhd_prevention/main.dart'; // 导入全局 navigatorKey + +/// 对话框模式 +enum DialogMode { text, input } + +class CustomAlertDialogTwo extends StatefulWidget { + final String title; + final String content; + final String hintText; + final String cancelText; + final String confirmText; + final VoidCallback? onCancel; + final VoidCallback? onConfirm; + final ValueChanged? onInputConfirm; + final DialogMode mode; + final bool force; + + const CustomAlertDialogTwo({ + Key? key, + required this.title, + this.content = '', + this.hintText = '', + this.cancelText = '取消', + this.confirmText = '确定', + this.onCancel, + this.onConfirm, + this.onInputConfirm, + this.mode = DialogMode.text, + this.force = false, + }) : super(key: key); + + // ------------------ 静态快捷方法 ------------------ + + static Future showConfirm( + BuildContext context, { + required String title, + String content = '', + String cancelText = '取消', + String confirmText = '确定', + bool barrierDismissible = true, + VoidCallback? onConfirm, + bool force = false, + }) async { + final result = await showDialog( + context: context, + barrierDismissible: force ? false : barrierDismissible, + builder: (_) => PopScope( + canPop: false, + child: CustomAlertDialogTwo( + title: title, + content: content, + cancelText: cancelText, + confirmText: confirmText, + onConfirm: onConfirm, + force: force, + ),) + ); + return result == true; + } + + static Future showAlert( + BuildContext context, { + required String title, + String content = '', + String confirmText = '确定', + bool barrierDismissible = true, + VoidCallback? onConfirm, + bool force = false, + }) async { + await showDialog( + context: context, + barrierDismissible: force ? false : barrierDismissible, + builder: (_) => CustomAlertDialogTwo( + title: title, + content: content, + cancelText: '', + confirmText: confirmText, + onConfirm: onConfirm, + force: force, + ), + ); + } + + static Future showInput( + BuildContext context, { + required String title, + String hintText = '', + String cancelText = '取消', + String confirmText = '确定', + bool barrierDismissible = true, + bool force = false, + }) async { + final result = await showDialog( + context: context, + barrierDismissible: force ? false : barrierDismissible, + builder: (_) => CustomAlertDialogTwo( + title: title, + hintText: hintText, + cancelText: cancelText, + confirmText: confirmText, + mode: DialogMode.input, + force: force, + ), + ); + // 取消/点遮罩会得到 null;确认会得到 String(可能为空串) + return result; + } + + + @override + _CustomAlertDialogTwoState createState() => _CustomAlertDialogTwoState(); +} + +class _CustomAlertDialogTwoState extends State { + late TextEditingController _controller; + bool _isClosing = false; + + @override + void initState() { + super.initState(); + _controller = TextEditingController(); + } + + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } + + bool get hasCancel => !widget.force && widget.cancelText.isNotEmpty; + + void _closeDialog([dynamic result]) { + if(result!=null&&result.isEmpty){ + ToastUtil.showNormal(context, '请输入内容'); + return; + } + if (_isClosing) return; + _isClosing = true; + + // 优先使用当前上下文导航 + if (mounted) { + Navigator.of(context).pop(result); + } else { + // 后备方案:使用全局导航键 + navigatorKey.currentState?.pop(result); + } + } + + @override + Widget build(BuildContext context) { + return PopScope( + canPop: !widget.force, + child: Dialog( + backgroundColor: Colors.transparent, + child: Container( + constraints: const BoxConstraints(minWidth: 280), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(8), + ), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + const SizedBox(height: 20), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 20), + child: Text( + widget.title, + style: const TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + ), + textAlign: TextAlign.center, + ), + ), + const SizedBox(height: 16), + if (widget.mode == DialogMode.text) + Padding( + padding: const EdgeInsets.symmetric(horizontal: 24), + child: Text( + widget.content, + style: const TextStyle( + fontSize: 16, + color: Colors.black54, + ), + textAlign: TextAlign.center, + ), + ) + else + Padding( + padding: const EdgeInsets.symmetric(horizontal: 20), + child: TextField( + controller: _controller, + autofocus: true, + decoration: InputDecoration( + hintText: widget.hintText, + border: const OutlineInputBorder(), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide(color: Colors.blue, width: 1), + borderRadius: BorderRadius.circular(4), + ), + isDense: true, + contentPadding: const EdgeInsets.symmetric( + vertical: 10, + horizontal: 10, + ), + ), + ), + ), + const SizedBox(height: 20), + const Divider(height: 1), + hasCancel + ? _buildDoubleButtons(context) + : _buildSingleButton(context), + ], + ), + ), + ), + ); + } + + Widget _buildDoubleButtons(BuildContext context) { + return Row( + children: [ + Expanded( + child: InkWell( + onTap: () { + widget.onCancel?.call(); + _closeDialog(widget.mode == DialogMode.text ? false : null); + }, + child: Container( + padding: const EdgeInsets.symmetric(vertical: 12), + alignment: Alignment.center, + child: Text( + widget.cancelText, + style: const TextStyle( + fontWeight: FontWeight.w500, + color: Colors.black87, + fontSize: 18, + ), + ), + ), + ), + ), + Container(width: 1, height: 48, color: Colors.grey[300]), + Expanded( + child: InkWell( + onTap: () { + if (widget.mode == DialogMode.text) { + widget.onConfirm?.call(); + _closeDialog(true); + } else { + final value = _controller.text.trim(); + widget.onInputConfirm?.call(value); + _closeDialog(value); + } + }, + child: Container( + padding: const EdgeInsets.symmetric(vertical: 12), + alignment: Alignment.center, + child: Text( + widget.confirmText, + style: const TextStyle( + color: Color(0xFF1C61FF), + fontWeight: FontWeight.w500, + fontSize: 18, + ), + ), + ), + ), + ), + ], + ); + } + + Widget _buildSingleButton(BuildContext context) { + return InkWell( + onTap: () { + if (widget.mode == DialogMode.text) { + widget.onConfirm?.call(); + _closeDialog(true); + } else { + final value = _controller.text.trim(); + widget.onInputConfirm?.call(value); + _closeDialog(value); + } + }, + child: Container( + width: double.infinity, + padding: const EdgeInsets.symmetric(vertical: 14), + alignment: Alignment.center, + child: Text( + widget.confirmText, + style: const TextStyle( + color: Color(0xFF1C61FF), + fontWeight: FontWeight.w500, + fontSize: 18, + ), + ), + ), + ); + } +} \ No newline at end of file diff --git a/lib/pages/notif/notif_detail_page.dart b/lib/pages/notif/notif_detail_page.dart index 2aea4c5..4406a7a 100644 --- a/lib/pages/notif/notif_detail_page.dart +++ b/lib/pages/notif/notif_detail_page.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_html/flutter_html.dart'; import 'package:qhd_prevention/customWidget/custom_alert_dialog.dart'; +import 'package:qhd_prevention/customWidget/custom_alert_dialog_two.dart'; import 'package:qhd_prevention/customWidget/custom_button.dart'; import 'package:qhd_prevention/customWidget/toast_util.dart'; import 'package:qhd_prevention/http/modules/notif_api.dart'; @@ -108,7 +109,7 @@ class _NotifDetailPageState extends State { child: SingleChildScrollView( child: Column( mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, // 左对齐 + crossAxisAlignment: CrossAxisAlignment.center, // 左对齐 children: [ Padding( padding: EdgeInsets.only(left: 10,right: 10), @@ -118,7 +119,7 @@ class _NotifDetailPageState extends State { SizedBox(height: 8), Padding( padding: EdgeInsets.only(left: 10,right: 10), - child: Text(time,), + child: Text(time,style: TextStyle(color: Colors.grey),), ), SizedBox(height: 8), Html( @@ -126,12 +127,13 @@ class _NotifDetailPageState extends State { ), SizedBox(height: 8), - if(isShowReply&&replyText.isEmpty) + // if(isShowReply&&replyText.isEmpty) CustomButton( height: 35, margin: EdgeInsets.only(right: 10), onPressed: () async { - final confirmed = await CustomAlertDialog.showInput( + + final confirmed = await CustomAlertDialogTwo.showInput( context, title: "回复", hintText: '输入内容', @@ -176,9 +178,9 @@ class _NotifDetailPageState extends State { final result = await NotifApi.replyContent(noticeReadId,content); LoadingDialogHelper.hide(); if (result['success']) { - ToastUtil.showNormal(context, '回复成功'); - Navigator.pop(context); - // onClose('关闭详情'); // 触发回调 + ToastUtil.showNormal(context, '回复成功'); + Navigator.pop(context); + // onClose('关闭详情'); // 触发回调 } } catch (e) { print('加载出错: $e');