import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; import 'package:worldhopper/config/constants.dart'; import 'package:worldhopper/providers/reading_progress_provider.dart'; import 'package:worldhopper/providers/server_provider.dart'; import 'package:worldhopper/widgets/worldhopper_app_bar.dart'; import 'package:worldhopper/widgets/recently_read_card.dart'; /// Screen displaying the user's reading history and library class LibraryScreen extends ConsumerWidget { const LibraryScreen({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { final recentlyReadAsync = ref.watch(recentlyReadProvider); return Scaffold( appBar: const WorldhopperAppBar( title: Text('Library'), ), body: RefreshIndicator( onRefresh: () async { ref.invalidate(recentlyReadProvider); }, child: recentlyReadAsync.when( data: (recentlyRead) { if (recentlyRead.isEmpty) { return _buildEmptyState(context, ref); } return CustomScrollView( slivers: [ // Recently read section header const SliverToBoxAdapter( child: Padding( padding: EdgeInsets.fromLTRB(16.0, 8.0, 16.0, 8.0), child: Text( 'Recently Read', style: TextStyle( fontSize: 20, fontWeight: FontWeight.bold, ), ), ), ), // Recently read grid SliverPadding( padding: const EdgeInsets.symmetric(horizontal: 16.0), sliver: SliverGrid( gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, childAspectRatio: 0.7, crossAxisSpacing: 16, mainAxisSpacing: 16, ), delegate: SliverChildBuilderDelegate( (context, index) { final progress = recentlyRead[index]; return RecentlyReadCard(progress: progress); }, childCount: recentlyRead.length, ), ), ), const SliverToBoxAdapter( child: SizedBox(height: 16), ), ], ); }, loading: () => const Center(child: CircularProgressIndicator()), error: (error, stack) => _buildErrorState(context, error), ), ), ); } Widget _buildEmptyState(BuildContext context, WidgetRef ref) { final serversAsync = ref.watch(serverListProvider); return serversAsync.when( data: (servers) { // Case 1: No servers configured if (servers.isEmpty) { return _buildNoServersState(context); } // Case 2: Servers exist but no reading history return _buildNoHistoryState(context); }, loading: () => const Center(child: CircularProgressIndicator()), error: (_, __) => _buildNoHistoryState(context), // Fallback ); } Widget _buildNoServersState(BuildContext context) { return Center( child: Padding( padding: const EdgeInsets.all(32.0), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( Icons.dns_outlined, size: 80, color: Theme.of(context).colorScheme.outline, ), const SizedBox(height: 24), Text( 'No Servers Configured', style: Theme.of(context).textTheme.headlineSmall, textAlign: TextAlign.center, ), const SizedBox(height: 12), Text( 'Add an OPDS server to start reading books', style: Theme.of(context).textTheme.bodyMedium?.copyWith( color: Theme.of(context).colorScheme.onSurface.withOpacity(0.6), ), textAlign: TextAlign.center, ), const SizedBox(height: 24), FilledButton.icon( onPressed: () => context.go(AppConstants.routeServerList), icon: const Icon(Icons.add), label: const Text('Add Server'), ), ], ), ), ); } Widget _buildNoHistoryState(BuildContext context) { return Center( child: Padding( padding: const EdgeInsets.all(32.0), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( Icons.auto_stories_outlined, size: 80, color: Theme.of(context).colorScheme.outline, ), const SizedBox(height: 24), Text( 'No Reading History', style: Theme.of(context).textTheme.headlineSmall, textAlign: TextAlign.center, ), const SizedBox(height: 12), Text( 'Start reading a book to see it here', style: Theme.of(context).textTheme.bodyMedium?.copyWith( color: Theme.of(context).colorScheme.onSurface.withOpacity(0.6), ), textAlign: TextAlign.center, ), const SizedBox(height: 24), FilledButton.icon( onPressed: () => context.go(AppConstants.routeServerList), icon: const Icon(Icons.dns), label: const Text('Browse Servers'), ), ], ), ), ); } Widget _buildErrorState(BuildContext context, Object error) { return Center( child: Padding( padding: const EdgeInsets.all(32.0), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( Icons.error_outline, size: 80, color: Theme.of(context).colorScheme.error, ), const SizedBox(height: 24), Text( 'Error Loading Library', style: Theme.of(context).textTheme.headlineSmall, textAlign: TextAlign.center, ), const SizedBox(height: 12), Text( error.toString(), style: Theme.of(context).textTheme.bodyMedium, textAlign: TextAlign.center, ), ], ), ), ); } }