import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../core/providers/model_download_provider.dart'; class ModelDownloadScreen extends ConsumerWidget { const ModelDownloadScreen({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { final downloadState = ref.watch(modelDownloadNotifierProvider); return Scaffold( body: SafeArea( child: Padding( padding: const EdgeInsets.all(32), child: downloadState.when( data: (progress) => progress == 0.0 ? _IdleView( onDownload: () => ref .read(modelDownloadNotifierProvider.notifier) .startDownload(), ) : _DownloadingView(progress: progress), loading: () => const Center(child: CircularProgressIndicator()), error: (e, _) => _ErrorView( error: e.toString(), onRetry: () { ref.read(modelDownloadNotifierProvider.notifier).reset(); }, ), ), ), ), ); } } class _IdleView extends StatelessWidget { const _IdleView({required this.onDownload}); final VoidCallback onDownload; @override Widget build(BuildContext context) { return Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Icon( Icons.auto_awesome, size: 64, color: Theme.of(context).colorScheme.primary, ), const SizedBox(height: 24), Text( 'On-device AI', style: Theme.of(context).textTheme.headlineSmall, textAlign: TextAlign.center, ), const SizedBox(height: 12), Text( 'DailyYou uses an on-device AI model to spot patterns in your moods ' 'and behaviour. Your data never leaves your phone.', style: Theme.of(context).textTheme.bodyMedium?.copyWith( color: Theme.of(context).colorScheme.onSurfaceVariant, ), textAlign: TextAlign.center, ), const SizedBox(height: 8), Text( 'The model is ~1.1 GB and only needs to be downloaded once.', style: Theme.of(context).textTheme.bodySmall?.copyWith( color: Theme.of(context).colorScheme.outline, ), textAlign: TextAlign.center, ), const SizedBox(height: 40), FilledButton.icon( onPressed: onDownload, icon: const Icon(Icons.download), label: const Text('Download model'), ), ], ); } } class _DownloadingView extends StatelessWidget { const _DownloadingView({required this.progress}); final double progress; @override Widget build(BuildContext context) { final pct = (progress * 100).toStringAsFixed(0); final done = progress >= 1.0; return Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Icon( done ? Icons.check_circle : Icons.downloading, size: 64, color: done ? Theme.of(context).colorScheme.primary : Theme.of(context).colorScheme.secondary, ), const SizedBox(height: 24), Text( done ? 'Ready!' : 'Downloading…', style: Theme.of(context).textTheme.headlineSmall, textAlign: TextAlign.center, ), const SizedBox(height: 24), LinearProgressIndicator(value: progress), const SizedBox(height: 8), Text( done ? 'Model downloaded successfully.' : '$pct% — keep the app open', style: Theme.of(context).textTheme.bodySmall?.copyWith( color: Theme.of(context).colorScheme.outline, ), textAlign: TextAlign.center, ), ], ); } } class _ErrorView extends StatelessWidget { const _ErrorView({required this.error, required this.onRetry}); final String error; final VoidCallback onRetry; @override Widget build(BuildContext context) { return Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Icon(Icons.error_outline, size: 64, color: Theme.of(context).colorScheme.error), const SizedBox(height: 24), Text( 'Download failed', style: Theme.of(context).textTheme.headlineSmall, textAlign: TextAlign.center, ), const SizedBox(height: 8), Text( 'Check your connection and try again.', style: Theme.of(context).textTheme.bodyMedium?.copyWith( color: Theme.of(context).colorScheme.onSurfaceVariant, ), textAlign: TextAlign.center, ), const SizedBox(height: 40), FilledButton.icon( onPressed: onRetry, icon: const Icon(Icons.refresh), label: const Text('Try again'), ), ], ); } }