// ignore_for_file: deprecated_member_use import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; import 'package:cached_network_image/cached_network_image.dart'; import '../../../bootstrap/supabase_client.dart'; import '../../../core/widgets/app_scaffold.dart'; import '../../../core/widgets/loading_indicator.dart'; import '../../../core/widgets/empty_state.dart'; import '../../../core/utils/date_time_utils.dart'; import '../application/profile_controller.dart'; import '../../achievements/application/achievements_controller.dart'; class ProfileScreen extends ConsumerStatefulWidget { const ProfileScreen({super.key}); @override ConsumerState createState() => _ProfileScreenState(); } class _ProfileScreenState extends ConsumerState { @override void initState() { super.initState(); final userId = currentSupabaseUserId; if (userId != null) { ref.read(profileControllerProvider.notifier).loadProfile(userId); } } @override Widget build(BuildContext context) { final profileState = ref.watch(profileControllerProvider); final achievementsState = ref.watch(achievementsControllerProvider); final userId = currentSupabaseUserId; if (userId == null) { return AppScaffold( title: 'Profile', body: Semantics( label: 'Not signed in', child: const EmptyState( icon: Icons.person_off, title: 'Not Signed In', subtitle: 'Please sign in to view your profile', ), ), ); } if (profileState.isLoading) { return const AppScaffold( body: Center(child: LoadingIndicator()), ); } if (profileState.errorMessage != null) { return AppScaffold( body: Semantics( label: 'Error loading profile', child: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ const Icon(Icons.error_outline, size: 48, color: Colors.red), const SizedBox(height: 16), Text( 'Error loading profile', style: Theme.of(context).textTheme.titleLarge, ), const SizedBox(height: 8), Text(profileState.errorMessage!), const SizedBox(height: 16), Semantics( button: true, label: 'Retry loading profile', child: ElevatedButton( onPressed: () { ref.read(profileControllerProvider.notifier).loadProfile(userId); }, child: const Text('Retry'), ), ), ], ), ), ), ); } final user = profileState.user; if (user == null) { return const AppScaffold( body: EmptyState( icon: Icons.person_off, title: 'Profile Not Found', subtitle: 'Your profile could not be loaded', ), ); } return AppScaffold( body: CustomScrollView( slivers: [ SliverAppBar( expandedHeight: 200, pinned: true, title: const Text('Profile'), flexibleSpace: FlexibleSpaceBar( background: Container( decoration: BoxDecoration( gradient: LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: [ Theme.of(context).colorScheme.primary.withOpacity(0.3), Theme.of(context).colorScheme.surface, ], ), ), ), ), actions: [ IconButton( icon: const Icon(Icons.settings), onPressed: () => context.push('/settings'), tooltip: 'Settings', ), ], ), SliverToBoxAdapter( child: Padding( padding: const EdgeInsets.all(24.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Center( child: Hero( tag: 'profile-avatar', child: Container( width: 100, height: 100, decoration: BoxDecoration( shape: BoxShape.circle, border: Border.all( color: Theme.of(context).colorScheme.primary, width: 3, ), ), child: ClipOval( child: user.avatarUrl != null ? CachedNetworkImage( imageUrl: user.avatarUrl!, fit: BoxFit.cover, placeholder: (context, url) => const Center( child: CircularProgressIndicator(), ), errorWidget: (context, url, error) => Icon( Icons.person, size: 50, color: Theme.of(context) .colorScheme .onSurfaceVariant, ), ) : Icon( Icons.person, size: 50, color: Theme.of(context) .colorScheme .onSurfaceVariant, ), ), ), ), ), const SizedBox(height: 16), Center( child: Text( user.username, style: Theme.of(context).textTheme.headlineSmall?.copyWith( fontWeight: FontWeight.bold, ), ), ), if (user.bio != null && user.bio!.isNotEmpty) ...[ const SizedBox(height: 8), Center( child: Text( user.bio!, style: Theme.of(context).textTheme.bodyMedium?.copyWith( color: Theme.of(context) .colorScheme .onSurfaceVariant, ), textAlign: TextAlign.center, ), ), ], const SizedBox(height: 24), _buildCountdownInfo(context, user), const SizedBox(height: 24), _buildStatsSection(context, user, achievementsState.level), const SizedBox(height: 24), _buildQuickActions(context), ], ), ), ), ], ), ); } Widget _buildCountdownInfo(BuildContext context, user) { final hasStarted = user.countdownStartDate != null; final hasEnded = user.countdownEndDate != null && user.countdownEndDate!.isBefore(DateTime.now()); return Card( elevation: 2, child: Padding( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Icon( hasEnded ? Icons.flag : Icons.timer_outlined, color: Theme.of(context).colorScheme.primary, ), const SizedBox(width: 8), Text( hasEnded ? 'Challenge Complete!' : '1356-Day Challenge', style: Theme.of(context).textTheme.titleMedium?.copyWith( fontWeight: FontWeight.bold, ), ), ], ), if (!hasStarted) ...[ const SizedBox(height: 12), Text( 'Your challenge hasn\'t started yet. Create your bucket list to begin!', style: Theme.of(context).textTheme.bodyMedium?.copyWith( color: Theme.of(context).colorScheme.onSurfaceVariant, ), ), ] else if (!hasEnded && user.countdownEndDate != null) ...[ const SizedBox(height: 12), _buildCountdownTimer(context, user.countdownEndDate!), const SizedBox(height: 8), Text( 'Started: ${DateTimeUtils.formatDate(user.countdownStartDate!)}', style: Theme.of(context).textTheme.bodySmall?.copyWith( color: Theme.of(context).colorScheme.onSurfaceVariant, ), ), ] else ...[ const SizedBox(height: 12), Text( 'Congratulations! You completed your 1356-day challenge.', style: Theme.of(context).textTheme.bodyMedium?.copyWith( color: Theme.of(context).colorScheme.primary, ), ), ], ], ), ), ); } Widget _buildCountdownTimer(BuildContext context, DateTime endDate) { final remaining = endDate.difference(DateTime.now()); final days = remaining.inDays; final hours = remaining.inHours % 24; final minutes = remaining.inMinutes % 60; final seconds = remaining.inSeconds % 60; return Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ _TimeUnit(label: 'Days', value: days.toString()), _TimeUnit(label: 'Hours', value: hours.toString().padLeft(2, '0')), _TimeUnit(label: 'Min', value: minutes.toString().padLeft(2, '0')), _TimeUnit(label: 'Sec', value: seconds.toString().padLeft(2, '0')), ], ); } Widget _buildStatsSection(BuildContext context, user, int? level) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( 'Your Stats', style: Theme.of(context).textTheme.titleMedium?.copyWith( fontWeight: FontWeight.bold, ), ), if (level != null) Container( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6), decoration: BoxDecoration( color: Theme.of(context).colorScheme.primary.withOpacity(0.08), borderRadius: BorderRadius.circular(999), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ const Icon( Icons.star_rounded, size: 16, ), const SizedBox(width: 4), Text( 'Level $level', style: Theme.of(context).textTheme.labelMedium?.copyWith( fontWeight: FontWeight.w600, ), ), ], ), ), ], ), const SizedBox(height: 12), Row( children: [ Expanded( child: _StatCard( icon: Icons.visibility, label: 'Profile', value: user.isPublicProfile ? 'Public' : 'Private', color: user.isPublicProfile ? Colors.green : Colors.orange, ), ), const SizedBox(width: 12), Expanded( child: _StatCard( icon: Icons.calendar_today, label: 'Member Since', value: DateTimeUtils.formatShortDate(user.createdAt), color: Theme.of(context).colorScheme.primary, ), ), ], ), ], ); } Widget _buildQuickActions(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Quick Actions', style: Theme.of(context).textTheme.titleMedium?.copyWith( fontWeight: FontWeight.bold, ), ), const SizedBox(height: 12), _ActionTile( icon: Icons.edit, title: 'Edit Profile', subtitle: 'Update your avatar, username, or bio', onTap: () => context.push('/profile/edit'), ), _ActionTile( icon: Icons.settings, title: 'Settings', subtitle: 'Manage app preferences and privacy', onTap: () => context.push('/settings'), ), _ActionTile( icon: Icons.info_outline, title: 'About the Challenge', subtitle: 'Learn more about the 1356-day challenge', onTap: () => context.push('/settings/about'), ), const SizedBox(height: 16), OutlinedButton.icon( onPressed: () async { final confirmed = await showDialog( context: context, builder: (dialogContext) => AlertDialog( title: const Text('Sign Out'), content: const Text('Are you sure you want to sign out?'), actions: [ TextButton( onPressed: () => Navigator.pop(dialogContext, false), child: const Text('Cancel'), ), TextButton( onPressed: () => Navigator.pop(dialogContext, true), style: TextButton.styleFrom( foregroundColor: Theme.of(context).colorScheme.error, ), child: const Text('Sign Out'), ), ], ), ); if (confirmed == true && context.mounted) { await signOutCurrentSupabaseUser(); if (context.mounted) { context.go('/'); } } }, icon: const Icon(Icons.logout), label: const Text('Sign Out'), style: OutlinedButton.styleFrom( foregroundColor: Theme.of(context).colorScheme.error, minimumSize: const Size(double.infinity, 48), ), ), ], ); } } class _TimeUnit extends StatelessWidget { final String label; final String value; const _TimeUnit({required this.label, required this.value}); @override Widget build(BuildContext context) { return Column( children: [ Container( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), decoration: BoxDecoration( color: Theme.of(context).colorScheme.primaryContainer, borderRadius: BorderRadius.circular(8), ), child: Text( value, style: Theme.of(context).textTheme.headlineSmall?.copyWith( fontWeight: FontWeight.bold, color: Theme.of(context).colorScheme.onPrimaryContainer, ), ), ), const SizedBox(height: 4), Text( label, style: Theme.of(context).textTheme.bodySmall?.copyWith( color: Theme.of(context).colorScheme.onSurfaceVariant, ), ), ], ); } } class _StatCard extends StatelessWidget { final IconData icon; final String label; final String value; final Color color; const _StatCard({ required this.icon, required this.label, required this.value, required this.color, }); @override Widget build(BuildContext context) { return Card( child: Padding( padding: const EdgeInsets.all(12.0), child: Column( children: [ Icon(icon, color: color, size: 24), const SizedBox(height: 8), Text( value, style: Theme.of(context).textTheme.titleSmall?.copyWith( fontWeight: FontWeight.bold, ), textAlign: TextAlign.center, ), const SizedBox(height: 4), Text( label, style: Theme.of(context).textTheme.bodySmall?.copyWith( color: Theme.of(context).colorScheme.onSurfaceVariant, ), textAlign: TextAlign.center, ), ], ), ), ); } } class _ActionTile extends StatelessWidget { final IconData icon; final String title; final String subtitle; final VoidCallback onTap; const _ActionTile({ required this.icon, required this.title, required this.subtitle, required this.onTap, }); @override Widget build(BuildContext context) { return ListTile( leading: Icon(icon), title: Text(title), subtitle: Text( subtitle, style: Theme.of(context).textTheme.bodySmall?.copyWith( color: Theme.of(context).colorScheme.onSurfaceVariant, ), ), trailing: const Icon(Icons.chevron_right), onTap: onTap, ); } }