import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; import 'package:worldhopper/l10n/app_localizations.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 l10n = AppLocalizations.of(context); final recentlyReadAsync = ref.watch(recentlyReadProvider); return Scaffold( appBar: WorldhopperAppBar( title: Text(l10n.libraryTitle), ), body: RefreshIndicator( onRefresh: () async { ref.invalidate(recentlyReadProvider); }, child: recentlyReadAsync.when( data: (recentlyRead) { if (recentlyRead.isEmpty) { return _buildEmptyState(context, ref, l10n); } return CustomScrollView( slivers: [ // Recently read section header SliverToBoxAdapter( child: Padding( padding: const EdgeInsets.fromLTRB(16.0, 8.0, 16.0, 8.0), child: Text( l10n.libraryRecentlyRead, style: const 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, l10n, error), ), ), ); } Widget _buildEmptyState( BuildContext context, WidgetRef ref, AppLocalizations l10n) { final serversAsync = ref.watch(serverListProvider); return serversAsync.when( data: (servers) { // Case 1: No servers configured if (servers.isEmpty) { return _buildNoServersState(context, l10n); } // Case 2: Servers exist but no reading history return _buildNoHistoryState(context, l10n); }, loading: () => const Center(child: CircularProgressIndicator()), error: (_, __) => _buildNoHistoryState(context, l10n), // Fallback ); } Widget _buildNoServersState(BuildContext context, AppLocalizations l10n) { 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( l10n.libraryNoServers, style: Theme.of(context).textTheme.headlineSmall, textAlign: TextAlign.center, ), const SizedBox(height: 12), Text( l10n.libraryNoServersSubtitle, style: Theme.of(context).textTheme.bodyMedium?.copyWith( color: Theme.of(context) .colorScheme .onSurface .withValues(alpha: 0.6), ), textAlign: TextAlign.center, ), const SizedBox(height: 24), FilledButton.icon( onPressed: () => context.go(AppConstants.routeServerList), icon: const Icon(Icons.add), label: Text(l10n.libraryAddServer), ), ], ), ), ); } Widget _buildNoHistoryState(BuildContext context, AppLocalizations l10n) { 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( l10n.libraryNoHistory, style: Theme.of(context).textTheme.headlineSmall, textAlign: TextAlign.center, ), const SizedBox(height: 12), Text( l10n.libraryNoHistorySubtitle, style: Theme.of(context).textTheme.bodyMedium?.copyWith( color: Theme.of(context) .colorScheme .onSurface .withValues(alpha: 0.6), ), textAlign: TextAlign.center, ), const SizedBox(height: 24), FilledButton.icon( onPressed: () => context.go(AppConstants.routeServerList), icon: const Icon(Icons.dns), label: Text(l10n.libraryBrowseServers), ), ], ), ), ); } Widget _buildErrorState( BuildContext context, AppLocalizations l10n, 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( l10n.libraryErrorLoading, 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, ), ], ), ), ); } }