import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../../../core/theme/app_colors.dart'; import '../../../../core/widgets/riotz_scaffold.dart'; import '../../../music/presentation/widgets/track_card.dart'; import '../../domain/models/discover_data_model.dart'; import '../../domain/models/trending_user_model.dart'; import '../providers/discover_providers.dart'; class DiscoverPage extends ConsumerStatefulWidget { const DiscoverPage({super.key}); @override ConsumerState createState() => _DiscoverPageState(); } class _DiscoverPageState extends ConsumerState { final _searchController = TextEditingController(); String _query = ''; @override void dispose() { _searchController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { final theme = Theme.of(context); final discoverAsync = ref.watch(discoverDataProvider); return RiotzScaffold( appBar: AppBar( title: const Text('RIOTZ // DISCOVER'), ), body: RefreshIndicator( color: AppColors.neonRed, backgroundColor: AppColors.black, onRefresh: () async => ref.invalidate(discoverDataProvider), child: ListView( padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 24), children: [ // Brutalist Search Bar TextField( controller: _searchController, decoration: const InputDecoration( prefixIcon: Icon(Icons.search, color: AppColors.white), hintText: 'SEARCH THE VOID...', ), onChanged: (value) => setState(() => _query = value.trim()), ), const SizedBox(height: 32), discoverAsync.when( loading: () => const Center( child: Padding( padding: EdgeInsets.all(48), child: CircularProgressIndicator(color: AppColors.neonRed), ), ), error: (error, _) => Center(child: Text('DISCOVERY OFFLINE: $error')), data: (data) { final filteredUsers = _filterUsers(data); final filteredTracks = data.trendingTracks.where((track) { final q = _query.toLowerCase(); return track.title.toLowerCase().contains(q) || track.username.toLowerCase().contains(q) || track.genreTag.toLowerCase().contains(q); }).toList(); final filteredPosts = data.trendingPosts.where((post) { final q = _query.toLowerCase(); return post.caption.toLowerCase().contains(q) || post.username.toLowerCase().contains(q); }).toList(); return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Trending Artists if (filteredUsers.isNotEmpty) ...[ _SectionHeader(title: 'TRENDING AGENTS', count: filteredUsers.length), const SizedBox(height: 16), SizedBox( height: 110, child: ListView.builder( scrollDirection: Axis.horizontal, itemCount: filteredUsers.length, itemBuilder: (context, index) { final user = filteredUsers[index]; return _TrendingUserCard(user: user); }, ), ), const SizedBox(height: 40), ], // Trending Tracks if (filteredTracks.isNotEmpty) ...[ _SectionHeader(title: 'SONIC FREQUENCIES', count: filteredTracks.length), const SizedBox(height: 16), ...filteredTracks.take(5).map((track) => TrackCard(track: track)), const SizedBox(height: 40), ], // Popular Posts if (filteredPosts.isNotEmpty) ...[ _SectionHeader(title: 'VISUAL CHAOS', count: filteredPosts.length), const SizedBox(height: 16), GridView.builder( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, crossAxisSpacing: 12, mainAxisSpacing: 12, childAspectRatio: 0.8, ), itemCount: filteredPosts.length, itemBuilder: (context, index) { final post = filteredPosts[index]; return _DiscoveryGridTile(post: post); }, ), ], if (filteredUsers.isEmpty && filteredTracks.isEmpty && filteredPosts.isEmpty) const Center( child: Padding( padding: EdgeInsets.all(48), child: Text('THE VOID IS EMPTY.'), ), ), ], ); }, ), ], ), ), ); } List _filterUsers(DiscoverDataModel data) { final q = _query.toLowerCase(); if (q.isEmpty) return data.trendingUsers; return data.trendingUsers .where((user) => user.username.toLowerCase().contains(q)) .toList(); } } class _SectionHeader extends StatelessWidget { const _SectionHeader({required this.title, required this.count}); final String title; final int count; @override Widget build(BuildContext context) { final theme = Theme.of(context); return Row( children: [ Text(title, style: theme.textTheme.labelLarge?.copyWith(letterSpacing: 2)), const Spacer(), Text('[$count]', style: theme.textTheme.labelLarge?.copyWith(color: AppColors.neonRed)), ], ); } } class _TrendingUserCard extends StatelessWidget { const _TrendingUserCard({required this.user}); final TrendingUserModel user; @override Widget build(BuildContext context) { return Container( width: 90, margin: const EdgeInsets.only(right: 12), child: Column( children: [ Container( width: 70, height: 70, decoration: BoxDecoration( border: Border.all(color: AppColors.white, width: 1.5), color: AppColors.surfaceLight, ), child: user.avatarUrl.isNotEmpty ? Image.network(user.avatarUrl, fit: BoxFit.cover) : const Icon(Icons.person, color: AppColors.grey), ), const SizedBox(height: 8), Text( user.username.toUpperCase(), style: const TextStyle(fontSize: 10, fontWeight: FontWeight.bold), maxLines: 1, overflow: TextOverflow.ellipsis, ), ], ), ); } } class _DiscoveryGridTile extends StatelessWidget { const _DiscoveryGridTile({required this.post}); final dynamic post; @override Widget build(BuildContext context) { return Container( decoration: BoxDecoration( border: Border.all(color: AppColors.border), color: AppColors.surface, ), child: Stack( fit: StackFit.expand, children: [ if (post.imageUrl.isNotEmpty) Image.network(post.imageUrl, fit: BoxFit.cover), Positioned( bottom: 0, left: 0, right: 0, child: Container( padding: const EdgeInsets.all(8), color: AppColors.black.withOpacity(0.7), child: Text( post.username.toUpperCase(), style: const TextStyle(fontSize: 10, fontWeight: FontWeight.bold), ), ), ), ], ), ); } }