import 'package:flutter/material.dart'; import 'package:shadcn_ui/shadcn_ui.dart'; import '../../core/theme/app_spacing.dart'; /// 现代弹窗模板 - 基于 modernization-v2.md 规范 /// /// 使用方法: /// ```dart /// ModernDialog.show( /// context: context, /// title: '确认操作', /// description: '确定要执行此操作吗?', /// actions: [ /// ModernDialogAction(label: '取消', isDestructive: false), /// ModernDialogAction(label: '确认', isPrimary: true), /// ], /// ); /// ``` class ModernDialog extends StatelessWidget { final String? title; final Widget? titleWidget; final String? description; final Widget? content; final List? actions; final VoidCallback? onClose; const ModernDialog({ super.key, this.title, this.titleWidget, this.description, this.content, this.actions, this.onClose, }); /// 显示现代弹窗 static Future show({ required BuildContext context, String? title, Widget? titleWidget, String? description, Widget? content, List? actions, bool barrierDismissible = true, }) { return showDialog( context: context, barrierDismissible: barrierDismissible, builder: (context) => ModernDialog( title: title, titleWidget: titleWidget, description: description, content: content, actions: actions, ), ); } /// 显示确认弹窗 static Future confirm({ required BuildContext context, required String title, String? description, String confirmText = '确认', String cancelText = '取消', bool isDestructive = false, }) async { final result = await show( context: context, title: title, description: description, actions: [ ModernDialogAction(label: cancelText, returnValue: false), ModernDialogAction( label: confirmText, returnValue: true, isPrimary: true, isDestructive: isDestructive, ), ], ); return result ?? false; } /// 显示信息弹窗 static Future info({ required BuildContext context, required String title, String? description, String buttonText = '知道了', }) { return show( context: context, title: title, description: description, actions: [ ModernDialogAction(label: buttonText, isPrimary: true), ], ); } @override Widget build(BuildContext context) { final theme = ShadTheme.of(context); return Dialog( shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(AppRadius.xl), ), backgroundColor: theme.colorScheme.card, child: Container( padding: const EdgeInsets.all(AppSpacing.lg), constraints: const BoxConstraints(maxWidth: 400), child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ // 标题 if (titleWidget != null) titleWidget! else if (title != null) Text( title!, style: theme.textTheme.h3.copyWith( fontWeight: FontWeight.w600, ), ), if (title != null || titleWidget != null) const SizedBox(height: AppSpacing.md), // 描述 if (description != null) ...[ Text( description!, style: theme.textTheme.muted, ), const SizedBox(height: AppSpacing.md), ], // 自定义内容 if (content != null) ...[ content!, const SizedBox(height: AppSpacing.lg), ], // 按钮 if (actions != null && actions!.isNotEmpty) Row( mainAxisAlignment: MainAxisAlignment.end, children: _buildActions(context), ), ], ), ), ); } List _buildActions(BuildContext context) { return actions!.asMap().entries.map((entry) { final index = entry.key; final action = entry.value; return Padding( padding: EdgeInsets.only(left: index > 0 ? AppSpacing.sm : 0), child: _buildActionButton(context, action), ); }).toList(); } Widget _buildActionButton(BuildContext context, ModernDialogAction action) { final theme = ShadTheme.of(context); if (action.isPrimary) { return ShadButton( backgroundColor: action.isDestructive ? theme.colorScheme.destructive : theme.colorScheme.primary, onPressed: () { Navigator.of(context).pop(action.returnValue); action.onPressed?.call(); }, child: Text(action.label), ); } return ShadButton.outline( onPressed: () { Navigator.of(context).pop(action.returnValue); action.onPressed?.call(); }, child: Text(action.label), ); } } /// 弹窗按钮配置 class ModernDialogAction { final String label; final dynamic returnValue; final bool isPrimary; final bool isDestructive; final VoidCallback? onPressed; const ModernDialogAction({ required this.label, this.returnValue, this.isPrimary = false, this.isDestructive = false, this.onPressed, }); }