mirror of
https://github.com/Dr-Blank/Vaani.git
synced 2026-07-06 01:11:45 +00:00
123
This commit is contained in:
parent
ead8850b2e
commit
0a26871bb1
6 changed files with 183 additions and 26 deletions
|
|
@ -6,7 +6,7 @@ part of 'api_provider.dart';
|
||||||
// RiverpodGenerator
|
// RiverpodGenerator
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
String _$audiobookshelfApiHash() => r'd7fbddf9ce2b463468c8d4db5a1bc4a53b7b7278';
|
String _$audiobookshelfApiHash() => r'ba34f6a16394cdc849b1bd63cd1f3f2472f04f69';
|
||||||
|
|
||||||
/// Copied from Dart SDK
|
/// Copied from Dart SDK
|
||||||
class _SystemHash {
|
class _SystemHash {
|
||||||
|
|
@ -170,7 +170,7 @@ class _AudiobookshelfApiProviderElement
|
||||||
Uri? get baseUrl => (origin as AudiobookshelfApiProvider).baseUrl;
|
Uri? get baseUrl => (origin as AudiobookshelfApiProvider).baseUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
String _$authenticatedApiHash() => r'13bba42fa712f173d3b72761ae9d544854df26d0';
|
String _$authenticatedApiHash() => r'd672c261b2da7b5091d64e2f7efb0da356ca32a5';
|
||||||
|
|
||||||
/// get the api instance for the authenticated user
|
/// get the api instance for the authenticated user
|
||||||
///
|
///
|
||||||
|
|
@ -191,7 +191,7 @@ final authenticatedApiProvider = Provider<AudiobookshelfApi>.internal(
|
||||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||||
// ignore: unused_element
|
// ignore: unused_element
|
||||||
typedef AuthenticatedApiRef = ProviderRef<AudiobookshelfApi>;
|
typedef AuthenticatedApiRef = ProviderRef<AudiobookshelfApi>;
|
||||||
String _$isServerAliveHash() => r'3afd608ced03a23fa7300d4a59368d170406ecc8';
|
String _$isServerAliveHash() => r'71f272f2102f43c1d2be212eff85faf2aadf916d';
|
||||||
|
|
||||||
/// ping the server to check if it is reachable
|
/// ping the server to check if it is reachable
|
||||||
///
|
///
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:shelfsdk/audiobookshelf_api.dart' as shelfsdk;
|
import 'package:shelfsdk/audiobookshelf_api.dart' as shelfsdk;
|
||||||
import 'package:vaani/api/library_item_provider.dart';
|
import 'package:vaani/api/library_item_provider.dart';
|
||||||
import 'package:vaani/constants/hero_tag_conventions.dart';
|
import 'package:vaani/constants/hero_tag_conventions.dart';
|
||||||
|
import 'package:vaani/constants/sizes.dart';
|
||||||
import 'package:vaani/features/downloads/providers/download_manager.dart'
|
import 'package:vaani/features/downloads/providers/download_manager.dart'
|
||||||
show
|
show
|
||||||
downloadHistoryProvider,
|
downloadHistoryProvider,
|
||||||
|
|
@ -93,6 +94,7 @@ class LibraryItemActions extends HookConsumerWidget {
|
||||||
},
|
},
|
||||||
icon: const Icon(Icons.share_rounded),
|
icon: const Icon(Icons.share_rounded),
|
||||||
),
|
),
|
||||||
|
LibItemDownButton(item.id),
|
||||||
// download button
|
// download button
|
||||||
LibItemDownloadButton(item: item),
|
LibItemDownloadButton(item: item),
|
||||||
|
|
||||||
|
|
@ -202,6 +204,139 @@ class LibraryItemActions extends HookConsumerWidget {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class LibItemDownButton extends HookConsumerWidget {
|
||||||
|
const LibItemDownButton(this.libraryItemId, {super.key});
|
||||||
|
final String libraryItemId;
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
return IconButton(
|
||||||
|
onPressed: () {
|
||||||
|
showModalBottomSheet(
|
||||||
|
context: context,
|
||||||
|
isScrollControlled: true,
|
||||||
|
builder: (context) {
|
||||||
|
return FractionallySizedBox(
|
||||||
|
heightFactor: 0.8,
|
||||||
|
child: LibItemDownSheet(libraryItemId),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
icon: const Icon(
|
||||||
|
Icons.download_sharp,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class LibItemDownSheet extends HookConsumerWidget {
|
||||||
|
const LibItemDownSheet(this.libraryItemId, {super.key});
|
||||||
|
final String libraryItemId;
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
// final downloadHistory =
|
||||||
|
// ref.watch(downloadHistoryProvider(group: libraryItemId));
|
||||||
|
final libraryItem = ref.watch(libraryItemProvider(libraryItemId));
|
||||||
|
return libraryItem.when(
|
||||||
|
data: (item) {
|
||||||
|
final book = item.media.asBookExpanded;
|
||||||
|
final tracks = book.tracks;
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.all(AppElementSizes.paddingRegular),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Text('下载管理'),
|
||||||
|
Expanded(
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
|
children: [
|
||||||
|
IconButton(
|
||||||
|
onPressed: () {},
|
||||||
|
icon: Icon(Icons.delete_outlined),
|
||||||
|
),
|
||||||
|
IconButton(
|
||||||
|
onPressed: () {},
|
||||||
|
icon: Icon(Icons.download_outlined),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: ListView.builder(
|
||||||
|
itemCount: tracks.length,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
final track = tracks[index];
|
||||||
|
return ListTile(
|
||||||
|
title: Text(track.title),
|
||||||
|
subtitle: Text(
|
||||||
|
// '${record.task.directory}/${record.task.baseDirectory}',
|
||||||
|
// track.metadata?.relPath ?? '',
|
||||||
|
item.relPath,
|
||||||
|
),
|
||||||
|
trailing: const Icon(
|
||||||
|
Icons.open_in_new_rounded,
|
||||||
|
),
|
||||||
|
onLongPress: () {
|
||||||
|
// show the delete dialog
|
||||||
|
// _showDialog(context, record.task);
|
||||||
|
},
|
||||||
|
onTap: () async {
|
||||||
|
// open the file location
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
loading: () => const Center(
|
||||||
|
child: CircularProgressIndicator(),
|
||||||
|
),
|
||||||
|
error: (error, stackTrace) => Center(
|
||||||
|
child: Text('Error: $error'),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _showDialog(context, task) {
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (context) {
|
||||||
|
return AlertDialog(
|
||||||
|
title: const Text('Delete'),
|
||||||
|
content: Text(
|
||||||
|
'Are you sure you want to delete ${task.filename}?',
|
||||||
|
),
|
||||||
|
actions: [
|
||||||
|
TextButton(
|
||||||
|
onPressed: () {
|
||||||
|
// delete the file
|
||||||
|
FileDownloader().database.deleteRecordWithId(
|
||||||
|
task.taskId,
|
||||||
|
);
|
||||||
|
Navigator.pop(context);
|
||||||
|
},
|
||||||
|
child: const Text('Yes'),
|
||||||
|
),
|
||||||
|
TextButton(
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.pop(context);
|
||||||
|
},
|
||||||
|
child: const Text('No'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class LibItemDownloadButton extends HookConsumerWidget {
|
class LibItemDownloadButton extends HookConsumerWidget {
|
||||||
const LibItemDownloadButton({
|
const LibItemDownloadButton({
|
||||||
super.key,
|
super.key,
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ import 'package:vaani/generated/l10n.dart';
|
||||||
import 'package:vaani/router/models/library_item_extras.dart';
|
import 'package:vaani/router/models/library_item_extras.dart';
|
||||||
import 'package:vaani/router/router.dart';
|
import 'package:vaani/router/router.dart';
|
||||||
import 'package:vaani/shared/extensions/model_conversions.dart';
|
import 'package:vaani/shared/extensions/model_conversions.dart';
|
||||||
|
import 'package:vaani/shared/extensions/style.dart';
|
||||||
import 'package:vaani/shared/icons/abs_icons.dart';
|
import 'package:vaani/shared/icons/abs_icons.dart';
|
||||||
import 'package:vaani/shared/widgets/skeletons.dart';
|
import 'package:vaani/shared/widgets/skeletons.dart';
|
||||||
|
|
||||||
|
|
@ -101,6 +102,7 @@ class LibraryPage extends HookConsumerWidget {
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
return LibraryPageItem(
|
return LibraryPageItem(
|
||||||
item: items[index],
|
item: items[index],
|
||||||
|
width: width,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
@ -133,12 +135,20 @@ class LibraryPageItem extends HookConsumerWidget {
|
||||||
const LibraryPageItem({
|
const LibraryPageItem({
|
||||||
super.key,
|
super.key,
|
||||||
required this.item,
|
required this.item,
|
||||||
|
required this.width,
|
||||||
});
|
});
|
||||||
final LibraryItem item;
|
final LibraryItem item;
|
||||||
|
final double width;
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final book = item.media.asBookMinified;
|
final book = item.media.asBookMinified;
|
||||||
final metadata = book.metadata.asBookMetadataMinified;
|
final metadata = book.metadata.asBookMetadataMinified;
|
||||||
|
final bodyLarge = Theme.of(context).textTheme.bodyLarge;
|
||||||
|
final bodySmall = Theme.of(context).textTheme.bodySmall;
|
||||||
|
final height = width +
|
||||||
|
15 +
|
||||||
|
(bodyLarge?.calculateHeight ?? 0) +
|
||||||
|
(bodySmall?.calculateHeight ?? 0);
|
||||||
return InkWell(
|
return InkWell(
|
||||||
onTap: () => context.pushNamed(
|
onTap: () => context.pushNamed(
|
||||||
Routes.libraryItem.name,
|
Routes.libraryItem.name,
|
||||||
|
|
@ -150,25 +160,28 @@ class LibraryPageItem extends HookConsumerWidget {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
borderRadius: BorderRadius.circular(10),
|
borderRadius: BorderRadius.circular(10),
|
||||||
child: Column(
|
child: SizedBox(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
height: height,
|
||||||
children: [
|
child: Column(
|
||||||
BookCoverWidget(itemId: item.id),
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
const SizedBox(height: 3),
|
children: [
|
||||||
Text(
|
Expanded(child: BookCoverWidget(itemId: item.id)),
|
||||||
metadata.title ?? '',
|
const SizedBox(height: 3),
|
||||||
maxLines: 1,
|
Text(
|
||||||
overflow: TextOverflow.ellipsis,
|
metadata.title ?? '',
|
||||||
style: Theme.of(context).textTheme.bodyLarge,
|
maxLines: 1,
|
||||||
),
|
overflow: TextOverflow.ellipsis,
|
||||||
const SizedBox(height: 2),
|
style: bodyLarge,
|
||||||
Text(
|
),
|
||||||
metadata.authorName ?? '',
|
const SizedBox(height: 2),
|
||||||
maxLines: 1,
|
Text(
|
||||||
overflow: TextOverflow.ellipsis,
|
metadata.authorName ?? '',
|
||||||
style: Theme.of(context).textTheme.bodySmall,
|
maxLines: 1,
|
||||||
),
|
overflow: TextOverflow.ellipsis,
|
||||||
],
|
style: bodySmall,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
7
lib/shared/extensions/style.dart
Normal file
7
lib/shared/extensions/style.dart
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
extension TextStyleExtension on TextStyle {
|
||||||
|
double get calculateHeight {
|
||||||
|
return (height ?? 0) * (fontSize ?? 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -213,10 +213,12 @@ class _BookOnShelfPlayButton extends HookConsumerWidget {
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final me = ref.watch(meProvider);
|
final me = ref.watch(meProvider);
|
||||||
final currentBook = ref.watch(currentBookProvider);
|
final currentBook = ref.watch(currentBookProvider);
|
||||||
final playing = ref.watch(playerStateProvider.select((v) => v.playing));
|
final playerStateNotifier = ref.watch(playerStateProvider.notifier);
|
||||||
|
final isLoading = playerStateNotifier.isLoading(libraryItemId);
|
||||||
final isCurrentBookSetInPlayer =
|
final isCurrentBookSetInPlayer =
|
||||||
currentBook?.libraryItemId == libraryItemId;
|
currentBook?.libraryItemId == libraryItemId;
|
||||||
final isPlayingThisBook = playing && isCurrentBookSetInPlayer;
|
final isPlayingThisBook =
|
||||||
|
playerStateNotifier.isPlaying() && isCurrentBookSetInPlayer;
|
||||||
|
|
||||||
final userProgress = me.valueOrNull?.mediaProgress
|
final userProgress = me.valueOrNull?.mediaProgress
|
||||||
?.firstWhereOrNull((element) => element.libraryItemId == libraryItemId);
|
?.firstWhereOrNull((element) => element.libraryItemId == libraryItemId);
|
||||||
|
|
@ -298,7 +300,7 @@ class _BookOnShelfPlayButton extends HookConsumerWidget {
|
||||||
icon: Hero(
|
icon: Hero(
|
||||||
tag: HeroTagPrefixes.libraryItemPlayButton + libraryItemId,
|
tag: HeroTagPrefixes.libraryItemPlayButton + libraryItemId,
|
||||||
child: DynamicItemPlayIcon(
|
child: DynamicItemPlayIcon(
|
||||||
// isLoading: isLoading,
|
isLoading: isLoading,
|
||||||
isBookCompleted: isBookCompleted,
|
isBookCompleted: isBookCompleted,
|
||||||
isPlayingThisBook: isPlayingThisBook,
|
isPlayingThisBook: isPlayingThisBook,
|
||||||
isCurrentBookSetInPlayer: isCurrentBookSetInPlayer,
|
isCurrentBookSetInPlayer: isCurrentBookSetInPlayer,
|
||||||
|
|
|
||||||
2
shelfsdk
2
shelfsdk
|
|
@ -1 +1 @@
|
||||||
Subproject commit 875c4bf90f5f08f24b90d3478322696ea29bd28f
|
Subproject commit c4d69ada95a8ad2db367bb3c5efd181668ceca6d
|
||||||
Loading…
Add table
Add a link
Reference in a new issue