import 'dart:async'; import 'package:flutter/material.dart'; import 'package:recording_tool/app/router/app_navigator.dart'; class AppToast { AppToast._(); static OverlayEntry? _entry; static Timer? _timer; static String messageOf(Object? error) { if (error == null) return '未知错误'; if (error is FormatException) return error.message; if (error is TimeoutException) return error.message ?? '请求超时'; var text = error.toString().trim(); const prefix = 'Exception: '; while (text.startsWith(prefix)) { text = text.substring(prefix.length).trimLeft(); } return text.isEmpty ? '未知错误' : text; } static void show( String message, { Duration duration = const Duration(seconds: 2), }) { final context = AppNavigator.context; if (context == null) return; _dismiss(); final overlay = Overlay.maybeOf(context, rootOverlay: true); if (overlay == null) return; _entry = OverlayEntry(builder: (_) => _ToastWidget(message: message)); overlay.insert(_entry!); _timer = Timer(duration, _dismiss); } static void showError(Object error) => show(messageOf(error)); static void _dismiss() { _timer?.cancel(); _timer = null; try { _entry?.remove(); } catch (_) { // OverlayEntry may already be removed. } _entry = null; } } class _ToastWidget extends StatelessWidget { const _ToastWidget({required this.message}); final String message; @override Widget build(BuildContext context) { return Positioned.fill( child: IgnorePointer( child: Center( child: Material( color: Colors.transparent, child: Container( constraints: BoxConstraints( maxWidth: MediaQuery.sizeOf(context).width * 0.8, ), padding: const EdgeInsets.symmetric(horizontal: 18, vertical: 11), decoration: BoxDecoration( color: Colors.black.withValues(alpha: 0.82), borderRadius: BorderRadius.circular(8), ), child: Text( message, textAlign: TextAlign.center, style: const TextStyle(color: Colors.white, fontSize: 14), ), ), ), ), ), ); } }