import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; import '../l10n/app_localizations.dart'; import '../network/api_response.dart'; /// 从异常中提取用户可读的错误信息(只取业务 message,去掉 Dio/错误码前缀) String extractErrorMessage(Object e) { if (e is DioException) { final data = e.response?.data; if (data is Map) { final msg = data['message']?.toString().trim() ?? data['msg']?.toString().trim() ?? ''; if (msg.isNotEmpty) { return msg; } } if (e.error is ApiException) { return (e.error as ApiException).message; } } if (e is ApiException) { return e.message; } return e.toString(); } /// 通用确认弹框,返回 true 表示用户点击了确定 Future showConfirmDialog( BuildContext context, { required String content, String? cancelText, String? confirmText, }) async { final l10n = AppLocalizations.of(context)!; final cancelLabel = cancelText ?? l10n.cancel; final confirmLabel = confirmText ?? l10n.confirm; final result = await showDialog( context: context, barrierDismissible: false, builder: (ctx) { final cs = Theme.of(ctx).colorScheme; return AlertDialog( shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)), contentPadding: const EdgeInsets.fromLTRB(24, 28, 24, 8), actionsPadding: EdgeInsets.zero, content: Text( content, textAlign: TextAlign.center, style: const TextStyle(fontSize: 15, height: 1.5), ), actions: [ const Divider(height: 1), Row( children: [ Expanded( child: TextButton( onPressed: () => Navigator.of(ctx).pop(false), style: TextButton.styleFrom( foregroundColor: Colors.grey, padding: const EdgeInsets.symmetric(vertical: 14), shape: const RoundedRectangleBorder( borderRadius: BorderRadius.only( bottomLeft: Radius.circular(16), ), ), ), child: Text(cancelLabel, style: const TextStyle(fontSize: 15)), ), ), const VerticalDivider(width: 1), Expanded( child: TextButton( onPressed: () => Navigator.of(ctx).pop(true), style: TextButton.styleFrom( foregroundColor: cs.onSurface, padding: const EdgeInsets.symmetric(vertical: 14), shape: const RoundedRectangleBorder( borderRadius: BorderRadius.only( bottomRight: Radius.circular(16), ), ), ), child: Text( confirmLabel, style: const TextStyle(fontSize: 15, fontWeight: FontWeight.w600), ), ), ), ], ), ], ); }, ); return result ?? false; } /// 通用提示弹框(仅一个确定按钮) Future showTipDialog( BuildContext context, { required String content, String? confirmText, }) async { final confirmLabel = confirmText ?? AppLocalizations.of(context)!.confirm; await showDialog( context: context, builder: (ctx) { final cs = Theme.of(ctx).colorScheme; return AlertDialog( shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)), contentPadding: const EdgeInsets.fromLTRB(24, 28, 24, 8), actionsPadding: EdgeInsets.zero, content: Text( content, textAlign: TextAlign.center, style: const TextStyle(fontSize: 15, height: 1.5), ), actions: [ const Divider(height: 1), SizedBox( width: double.infinity, child: TextButton( onPressed: () => Navigator.of(ctx).pop(), style: TextButton.styleFrom( foregroundColor: cs.onSurface, padding: const EdgeInsets.symmetric(vertical: 14), shape: const RoundedRectangleBorder( borderRadius: BorderRadius.only( bottomLeft: Radius.circular(16), bottomRight: Radius.circular(16), ), ), ), child: Text( confirmLabel, style: const TextStyle(fontSize: 15, fontWeight: FontWeight.w600), ), ), ), ], ); }, ); }