worldhopper/lib/screens/library/library_screen.dart
Felipe M. ea068f6827
refactor: remove statistics section from library screen
Removed the "In Progress" and "Completed" statistics card from the
top of the library view. The screen now shows only the recently read
books grid for a cleaner, more focused interface.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-28 20:25:08 +01:00

205 lines
6.6 KiB
Dart

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,
),
],
),
),
);
}
}