mirror of
https://github.com/Dr-Blank/Vaani.git
synced 2025-12-27 13:29:31 +00:00
Fix compilation errors in library browser views: - Use serverUrl instead of url on AudiobookShelfServer model - Use authToken instead of token on AuthenticatedUser model - Add all required variant handlers to Series.maybeMap call These changes align with the actual model definitions in the codebase.
163 lines
5.3 KiB
Dart
163 lines
5.3 KiB
Dart
import 'package:cached_network_image/cached_network_image.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
|
import 'package:shelfsdk/audiobookshelf_api.dart';
|
|
import 'package:vaani/api/api_provider.dart';
|
|
import 'package:vaani/api/library_browser_provider.dart';
|
|
import 'package:vaani/settings/api_settings_provider.dart';
|
|
|
|
class LibraryAuthorsPage extends HookConsumerWidget {
|
|
const LibraryAuthorsPage({super.key});
|
|
|
|
@override
|
|
Widget build(BuildContext context, WidgetRef ref) {
|
|
final authorsAsync = ref.watch(libraryAuthorsProvider);
|
|
|
|
return Scaffold(
|
|
appBar: AppBar(
|
|
title: const Text('Authors'),
|
|
),
|
|
body: authorsAsync.when(
|
|
data: (authors) {
|
|
if (authors.isEmpty) {
|
|
return const Center(
|
|
child: Text('No authors found'),
|
|
);
|
|
}
|
|
|
|
return GridView.builder(
|
|
padding: const EdgeInsets.all(16),
|
|
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
|
|
crossAxisCount: 2,
|
|
childAspectRatio: 0.75,
|
|
crossAxisSpacing: 16,
|
|
mainAxisSpacing: 16,
|
|
),
|
|
itemCount: authors.length,
|
|
itemBuilder: (context, index) {
|
|
final author = authors[index];
|
|
return AuthorCard(author: author);
|
|
},
|
|
);
|
|
},
|
|
loading: () => const Center(
|
|
child: CircularProgressIndicator(),
|
|
),
|
|
error: (error, stack) => Center(
|
|
child: Column(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
children: [
|
|
const Icon(Icons.error_outline, size: 48, color: Colors.red),
|
|
const SizedBox(height: 16),
|
|
Text('Error loading authors: $error'),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
class AuthorCard extends HookConsumerWidget {
|
|
const AuthorCard({
|
|
super.key,
|
|
required this.author,
|
|
});
|
|
|
|
final Author author;
|
|
|
|
@override
|
|
Widget build(BuildContext context, WidgetRef ref) {
|
|
final apiSettings = ref.watch(apiSettingsProvider);
|
|
final api = ref.watch(authenticatedApiProvider);
|
|
|
|
// Determine the author variant and extract relevant data
|
|
final String? imagePath = author.map(
|
|
(base) => base.imagePath,
|
|
minified: (minified) => null,
|
|
expanded: (expanded) => expanded.imagePath,
|
|
);
|
|
|
|
final int? numBooks = author.map(
|
|
(base) => base.libraryItems?.length,
|
|
minified: (minified) => null,
|
|
expanded: (expanded) => expanded.numBooks,
|
|
);
|
|
|
|
// Build the image URL if imagePath is available
|
|
String? imageUrl;
|
|
if (imagePath != null && apiSettings.activeServer != null) {
|
|
imageUrl = '${apiSettings.activeServer!.serverUrl}/api/authors/${author.id}/image';
|
|
}
|
|
|
|
return Card(
|
|
clipBehavior: Clip.antiAlias,
|
|
child: InkWell(
|
|
onTap: () {
|
|
// TODO: Navigate to author detail page
|
|
ScaffoldMessenger.of(context).showSnackBar(
|
|
SnackBar(
|
|
content: Text('Tapped on ${author.name}'),
|
|
duration: const Duration(seconds: 1),
|
|
),
|
|
);
|
|
},
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
children: [
|
|
Expanded(
|
|
flex: 3,
|
|
child: imageUrl != null
|
|
? CachedNetworkImage(
|
|
imageUrl: imageUrl,
|
|
httpHeaders: {
|
|
'Authorization': 'Bearer ${apiSettings.activeUser?.authToken}',
|
|
},
|
|
fit: BoxFit.cover,
|
|
placeholder: (context, url) => Container(
|
|
color: Theme.of(context).colorScheme.surfaceContainerHighest,
|
|
child: const Center(
|
|
child: CircularProgressIndicator(),
|
|
),
|
|
),
|
|
errorWidget: (context, url, error) => Container(
|
|
color: Theme.of(context).colorScheme.surfaceContainerHighest,
|
|
child: const Icon(Icons.person, size: 48),
|
|
),
|
|
)
|
|
: Container(
|
|
color: Theme.of(context).colorScheme.surfaceContainerHighest,
|
|
child: const Icon(Icons.person, size: 48),
|
|
),
|
|
),
|
|
Expanded(
|
|
flex: 2,
|
|
child: Padding(
|
|
padding: const EdgeInsets.all(8.0),
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
children: [
|
|
Text(
|
|
author.name,
|
|
style: Theme.of(context).textTheme.titleMedium,
|
|
maxLines: 2,
|
|
overflow: TextOverflow.ellipsis,
|
|
),
|
|
if (numBooks != null) ...[
|
|
const SizedBox(height: 4),
|
|
Text(
|
|
'$numBooks ${numBooks == 1 ? 'book' : 'books'}',
|
|
style: Theme.of(context).textTheme.bodySmall,
|
|
),
|
|
],
|
|
],
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|