import 'package:flutter/material.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:trainhub_flutter/core/constants/ui_constants.dart'; import 'package:trainhub_flutter/core/theme/app_colors.dart'; import 'package:trainhub_flutter/presentation/settings/ai_model_settings_state.dart'; class DownloadProgress extends StatelessWidget { const DownloadProgress({super.key, required this.modelState}); final AiModelSettingsState modelState; @override Widget build(BuildContext context) { final pct = (modelState.progress * 100).toStringAsFixed(1); return Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( width: 56, height: 56, decoration: BoxDecoration( color: AppColors.accentMuted, borderRadius: BorderRadius.circular(14), ), child: const Icon( Icons.download_rounded, color: AppColors.accent, size: 28, ), ), const SizedBox(height: UIConstants.spacing24), Text( 'Setting up AI models\u2026', style: GoogleFonts.inter( fontSize: 22, fontWeight: FontWeight.w700, color: AppColors.textPrimary, letterSpacing: -0.3, ), ), const SizedBox(height: UIConstants.spacing8), Text( 'Please keep the app open. This only happens once.', style: GoogleFonts.inter( fontSize: 13, color: AppColors.textSecondary, ), ), const SizedBox(height: UIConstants.spacing32), ClipRRect( borderRadius: BorderRadius.circular(4), child: LinearProgressIndicator( value: modelState.progress, minHeight: 6, backgroundColor: AppColors.zinc800, valueColor: const AlwaysStoppedAnimation(AppColors.accent), ), ), const SizedBox(height: UIConstants.spacing12), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Expanded( child: Text( modelState.currentTask, style: GoogleFonts.inter( fontSize: 13, color: AppColors.textSecondary, ), maxLines: 1, overflow: TextOverflow.ellipsis, ), ), Text( '$pct %', style: GoogleFonts.inter( fontSize: 13, fontWeight: FontWeight.w600, color: AppColors.accent, ), ), ], ), if (modelState.errorMessage != null) ...[ const SizedBox(height: UIConstants.spacing16), ErrorBanner(message: modelState.errorMessage!), ], ], ); } } class ErrorBanner extends StatelessWidget { const ErrorBanner({super.key, required this.message}); final String message; @override Widget build(BuildContext context) { return Container( padding: const EdgeInsets.all(UIConstants.spacing12), decoration: BoxDecoration( color: AppColors.destructiveMuted, borderRadius: BorderRadius.circular(UIConstants.smallBorderRadius), border: Border.all( color: AppColors.destructive.withValues(alpha: 0.4), ), ), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Icon( Icons.error_outline_rounded, color: AppColors.destructive, size: 16, ), const SizedBox(width: UIConstants.spacing8), Expanded( child: Text( message, style: GoogleFonts.inter( fontSize: 12, color: AppColors.destructive, height: 1.5, ), ), ), ], ), ); } }