import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:image_picker/image_picker.dart'; import '../../../../core/theme/app_colors.dart'; import '../../../../core/widgets/riotz_scaffold.dart'; import '../../../../core/widgets/riotz_button.dart'; import '../../../auth/presentation/providers/auth_provider.dart'; import '../../../music/presentation/providers/music_providers.dart'; import '../../../music/presentation/widgets/track_card.dart'; import '../../domain/models/profile_model.dart'; import '../../domain/models/profile_stats_model.dart'; import '../providers/profile_providers.dart'; class ProfilePage extends ConsumerStatefulWidget { const ProfilePage({super.key}); @override ConsumerState createState() => _ProfilePageState(); } class _ProfilePageState extends ConsumerState with SingleTickerProviderStateMixin { late TabController _tabController; final _usernameController = TextEditingController(); final _bioController = TextEditingController(); final _picker = ImagePicker(); @override void initState() { super.initState(); _tabController = TabController(length: 2, vsync: this); } @override void dispose() { _tabController.dispose(); _usernameController.dispose(); _bioController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { final theme = Theme.of(context); ref.listen(profileControllerProvider, (_, next) { next.whenOrNull( data: (_) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar( backgroundColor: AppColors.success, content: Text('IDENTITY UPDATED.', style: TextStyle(color: AppColors.black, fontWeight: FontWeight.bold)), ), ); ref.invalidate(myProfileStatsProvider); }, error: (error, _) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( backgroundColor: AppColors.bloodRed, content: Text(error.toString().toUpperCase()), ), ); }, ); }); final profileAsync = ref.watch(myProfileProvider); final statsAsync = ref.watch(myProfileStatsProvider); final updating = ref.watch(profileControllerProvider).isLoading; final currentUser = ref.watch(authServiceProvider).currentUser; return RiotzScaffold( appBar: AppBar( title: const Text('RIOTZ // IDENTITY'), ), body: profileAsync.when( loading: () => const Center(child: CircularProgressIndicator(color: AppColors.neonRed)), error: (error, _) => Center(child: Text('ERROR: $error')), data: (profile) { _syncControllers(profile); return Column( children: [ Expanded( child: ListView( padding: const EdgeInsets.symmetric(horizontal: 32, vertical: 24), children: [ // Profile Header Center( child: Stack( children: [ Container( width: 120, height: 120, decoration: BoxDecoration( border: Border.all(color: AppColors.neonRed, width: 2), color: AppColors.surfaceLight, ), child: profile.avatarUrl.isNotEmpty ? Image.network(profile.avatarUrl, fit: BoxFit.cover) : const Icon(Icons.person, size: 60, color: AppColors.grey), ), Positioned( right: -4, bottom: -4, child: IconButton( onPressed: updating ? null : _pickAndUploadAvatar, icon: Container( padding: const EdgeInsets.all(4), color: AppColors.neonRed, child: const Icon(Icons.edit, color: AppColors.white, size: 18), ), ), ), ], ), ), const SizedBox(height: 32), _StatsSection(statsAsync: statsAsync), const SizedBox(height: 32), // Tabs TabBar( controller: _tabController, indicatorColor: AppColors.neonRed, labelColor: AppColors.white, unselectedLabelColor: AppColors.grey, tabs: const [ Tab(text: 'IDENTITY'), Tab(text: 'TRACKS'), ], ), const SizedBox(height: 24), SizedBox( height: 400, // Fixed height for tab content in ListView child: TabBarView( controller: _tabController, children: [ // Identity Tab SingleChildScrollView( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('USERNAME', style: theme.textTheme.labelLarge?.copyWith(color: AppColors.grey)), const SizedBox(height: 8), TextField( controller: _usernameController, decoration: const InputDecoration(hintText: 'ENTER ALIAS'), ), const SizedBox(height: 24), Text('BIO // MANIFESTO', style: theme.textTheme.labelLarge?.copyWith(color: AppColors.grey)), const SizedBox(height: 8), TextField( controller: _bioController, decoration: const InputDecoration(hintText: 'DESCRIBE THE CHAOS'), minLines: 3, maxLines: 5, ), const SizedBox(height: 32), RiotzButton( label: 'UPDATE IDENTITY', isLoading: updating, onPressed: () async { await ref .read(profileControllerProvider.notifier) .saveProfile( username: _usernameController.text, bio: _bioController.text, ); }, ), ], ), ), // Tracks Tab currentUser == null ? const Center(child: Text('LOG IN TO SEE TRACKS')) : Consumer( builder: (context, ref, child) { final tracksAsync = ref.watch(userTracksProvider(currentUser.id)); return tracksAsync.when( loading: () => const Center(child: CircularProgressIndicator(color: AppColors.neonRed)), error: (err, _) => Center(child: Text('ERROR: $err')), data: (tracks) { if (tracks.isEmpty) { return const Center(child: Text('NO TRACKS BROADCASTED.')); } return ListView.builder( padding: EdgeInsets.zero, itemCount: tracks.length, itemBuilder: (context, index) => TrackCard(track: tracks[index]), ); }, ); }, ), ], ), ), ], ), ), ], ); }, ), ); } void _syncControllers(ProfileModel profile) { if (_usernameController.text != profile.username) { _usernameController.text = profile.username; } if (_bioController.text != profile.bio) { _bioController.text = profile.bio; } } Future _pickAndUploadAvatar() async { final picked = await _picker.pickImage( source: ImageSource.gallery, imageQuality: 85, maxWidth: 1200, ); if (picked == null) return; final bytes = await picked.readAsBytes(); final ext = picked.name.split('.').last.toLowerCase(); if (!mounted) return; await ref.read(profileControllerProvider.notifier).uploadAvatar( bytes: bytes, extension: ext.isEmpty ? 'jpg' : ext, ); } } class _StatsSection extends StatelessWidget { const _StatsSection({required this.statsAsync}); final AsyncValue statsAsync; @override Widget build(BuildContext context) { return statsAsync.when( loading: () => const Center(child: CircularProgressIndicator(color: AppColors.neonRed)), error: (error, _) => Text('STATS OFFLINE: $error'), data: (stats) => Row( mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ _StatItem(label: 'POSTS', value: stats.postsCount.toString()), _StatItem(label: 'CHAOS', value: stats.commentsCount.toString()), _StatItem(label: 'TRACKS', value: stats.tracksCount.toString()), ], ), ); } } class _StatItem extends StatelessWidget { const _StatItem({ required this.label, required this.value, }); final String label; final String value; @override Widget build(BuildContext context) { final theme = Theme.of(context); return Column( children: [ Text(value, style: theme.textTheme.headlineLarge), Text(label, style: theme.textTheme.labelLarge?.copyWith(color: AppColors.grey, fontSize: 10)), ], ); } }