import 'package:flutter/material.dart'; import 'package:shadcn_ui/shadcn_ui.dart'; import '../core/app_colors.dart'; import '../core/app_design_tokens.dart'; enum AppToastType { success, error, warning, info } class AppToast { AppToast._(); static OverlayEntry? _entry; static void show( BuildContext context, String message, { AppToastType type = AppToastType.info, Duration duration = const Duration(milliseconds: 2200), }) { _entry?.remove(); final overlay = Overlay.of(context); final visual = _visual(type); _entry = OverlayEntry( builder: (ctx) => Positioned( top: MediaQuery.paddingOf(ctx).top + 62, left: 20, right: 20, child: IgnorePointer( child: Center( child: Material( color: Colors.transparent, child: Container( constraints: BoxConstraints( minHeight: 42, maxWidth: MediaQuery.sizeOf(ctx).width * 0.82, ), padding: const EdgeInsets.symmetric( horizontal: 14, vertical: 10, ), decoration: BoxDecoration( color: Colors.white, borderRadius: AppRadius.lgBorder, border: Border.all( color: visual.color.withValues(alpha: 0.20), ), boxShadow: AppShadows.floating, ), child: Row( mainAxisSize: MainAxisSize.min, children: [ Icon(visual.icon, size: 18, color: visual.color), const SizedBox(width: 8), Flexible( child: Text( message, maxLines: 2, overflow: TextOverflow.ellipsis, style: const TextStyle( fontSize: 15, fontWeight: FontWeight.w700, color: AppColors.textPrimary, height: 1.25, ), ), ), ], ), ), ), ), ), ), ); overlay.insert(_entry!); Future.delayed(duration, () { _entry?.remove(); _entry = null; }); } static ({IconData icon, Color color}) _visual(AppToastType type) { return switch (type) { AppToastType.success => ( icon: LucideIcons.circleCheck, color: AppColors.successText, ), AppToastType.error => ( icon: LucideIcons.circleX, color: AppColors.errorText, ), AppToastType.warning => ( icon: LucideIcons.triangleAlert, color: AppColors.warningText, ), AppToastType.info => (icon: LucideIcons.info, color: AppColors.health), }; } }