mirror of
https://github.com/Dr-Blank/Vaani.git
synced 2025-12-11 13:39:29 +00:00
refactor: update cover image handling to use item IDs and simplify library item actions
This commit is contained in:
parent
d25d23a0b7
commit
405d625cdc
15 changed files with 305 additions and 362 deletions
|
|
@ -4,6 +4,7 @@ import 'package:logging/logging.dart';
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
import 'package:shelfsdk/audiobookshelf_api.dart';
|
import 'package:shelfsdk/audiobookshelf_api.dart';
|
||||||
import 'package:vaani/api/api_provider.dart';
|
import 'package:vaani/api/api_provider.dart';
|
||||||
|
import 'package:vaani/api/library_item_provider.dart';
|
||||||
import 'package:vaani/db/cache_manager.dart';
|
import 'package:vaani/db/cache_manager.dart';
|
||||||
|
|
||||||
/// provides cover images for the audiobooks
|
/// provides cover images for the audiobooks
|
||||||
|
|
@ -19,52 +20,53 @@ final _logger = Logger('cover_image_provider');
|
||||||
@Riverpod(keepAlive: true)
|
@Riverpod(keepAlive: true)
|
||||||
class CoverImage extends _$CoverImage {
|
class CoverImage extends _$CoverImage {
|
||||||
@override
|
@override
|
||||||
Stream<Uint8List> build(LibraryItem libraryItem) async* {
|
Stream<Uint8List> build(String itemId) async* {
|
||||||
final api = ref.watch(authenticatedApiProvider);
|
final api = ref.watch(authenticatedApiProvider);
|
||||||
|
|
||||||
// ! artifical delay for testing
|
// ! artifical delay for testing
|
||||||
// await Future.delayed(const Duration(seconds: 2));
|
// await Future.delayed(const Duration(seconds: 2));
|
||||||
|
|
||||||
// try to get the image from the cache
|
// try to get the image from the cache
|
||||||
final file = await imageCacheManager.getFileFromMemory(libraryItem.id) ??
|
final file = await imageCacheManager.getFileFromMemory(itemId) ??
|
||||||
await imageCacheManager.getFileFromCache(libraryItem.id);
|
await imageCacheManager.getFileFromCache(itemId);
|
||||||
|
|
||||||
if (file != null) {
|
if (file != null) {
|
||||||
// if the image is in the cache, yield it
|
// if the image is in the cache, yield it
|
||||||
_logger.fine(
|
_logger.fine(
|
||||||
'cover image found in cache for ${libraryItem.id} at ${file.file.path}',
|
'cover image found in cache for $itemId at ${file.file.path}',
|
||||||
);
|
);
|
||||||
yield await file.file.readAsBytes();
|
yield await file.file.readAsBytes();
|
||||||
|
final libraryItem = await ref.watch(libraryItemProvider(itemId).future);
|
||||||
// return if no need to fetch from the server
|
// return if no need to fetch from the server
|
||||||
if (libraryItem.updatedAt.isBefore(await file.file.lastModified())) {
|
if (libraryItem.updatedAt.isBefore(await file.file.lastModified())) {
|
||||||
_logger.fine(
|
_logger.fine(
|
||||||
'cover image is up to date for ${libraryItem.id}, no need to fetch from the server',
|
'cover image is up to date for $itemId, no need to fetch from the server',
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
_logger.fine(
|
_logger.fine(
|
||||||
'cover image stale for ${libraryItem.id}, fetching from the server',
|
'cover image stale for $itemId, fetching from the server',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
_logger.fine('cover image not found in cache for ${libraryItem.id}');
|
_logger.fine('cover image not found in cache for $itemId');
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if the image is in the cache
|
// check if the image is in the cache
|
||||||
final coverImage = await api.items.getCover(
|
final coverImage = await api.items.getCover(
|
||||||
libraryItemId: libraryItem.id,
|
libraryItemId: itemId,
|
||||||
parameters: const GetImageReqParams(width: 1200),
|
parameters: const GetImageReqParams(width: 1200),
|
||||||
);
|
);
|
||||||
// save the image to the cache
|
// save the image to the cache
|
||||||
if (coverImage != null) {
|
if (coverImage != null) {
|
||||||
final newFile = await imageCacheManager.putFile(
|
final newFile = await imageCacheManager.putFile(
|
||||||
libraryItem.id,
|
itemId,
|
||||||
coverImage,
|
coverImage,
|
||||||
key: libraryItem.id,
|
key: itemId,
|
||||||
fileExtension: 'jpg',
|
fileExtension: 'jpg',
|
||||||
);
|
);
|
||||||
_logger.fine(
|
_logger.fine(
|
||||||
'cover image fetched for for ${libraryItem.id}, file time: ${await newFile.lastModified()}',
|
'cover image fetched for for $itemId, file time: ${await newFile.lastModified()}',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ part of 'image_provider.dart';
|
||||||
// RiverpodGenerator
|
// RiverpodGenerator
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
String _$coverImageHash() => r'702afafa217dfcbb290837caf21cc1ef54defd55';
|
String _$coverImageHash() => r'89cc4783cbc76bb41beae34384d92fb277135c75';
|
||||||
|
|
||||||
/// Copied from Dart SDK
|
/// Copied from Dart SDK
|
||||||
class _SystemHash {
|
class _SystemHash {
|
||||||
|
|
@ -30,10 +30,10 @@ class _SystemHash {
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class _$CoverImage extends BuildlessStreamNotifier<Uint8List> {
|
abstract class _$CoverImage extends BuildlessStreamNotifier<Uint8List> {
|
||||||
late final LibraryItem libraryItem;
|
late final String itemId;
|
||||||
|
|
||||||
Stream<Uint8List> build(
|
Stream<Uint8List> build(
|
||||||
LibraryItem libraryItem,
|
String itemId,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -48,10 +48,10 @@ class CoverImageFamily extends Family<AsyncValue<Uint8List>> {
|
||||||
|
|
||||||
/// See also [CoverImage].
|
/// See also [CoverImage].
|
||||||
CoverImageProvider call(
|
CoverImageProvider call(
|
||||||
LibraryItem libraryItem,
|
String itemId,
|
||||||
) {
|
) {
|
||||||
return CoverImageProvider(
|
return CoverImageProvider(
|
||||||
libraryItem,
|
itemId,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -60,7 +60,7 @@ class CoverImageFamily extends Family<AsyncValue<Uint8List>> {
|
||||||
covariant CoverImageProvider provider,
|
covariant CoverImageProvider provider,
|
||||||
) {
|
) {
|
||||||
return call(
|
return call(
|
||||||
provider.libraryItem,
|
provider.itemId,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -84,9 +84,9 @@ class CoverImageProvider
|
||||||
extends StreamNotifierProviderImpl<CoverImage, Uint8List> {
|
extends StreamNotifierProviderImpl<CoverImage, Uint8List> {
|
||||||
/// See also [CoverImage].
|
/// See also [CoverImage].
|
||||||
CoverImageProvider(
|
CoverImageProvider(
|
||||||
LibraryItem libraryItem,
|
String itemId,
|
||||||
) : this._internal(
|
) : this._internal(
|
||||||
() => CoverImage()..libraryItem = libraryItem,
|
() => CoverImage()..itemId = itemId,
|
||||||
from: coverImageProvider,
|
from: coverImageProvider,
|
||||||
name: r'coverImageProvider',
|
name: r'coverImageProvider',
|
||||||
debugGetCreateSourceHash:
|
debugGetCreateSourceHash:
|
||||||
|
|
@ -96,7 +96,7 @@ class CoverImageProvider
|
||||||
dependencies: CoverImageFamily._dependencies,
|
dependencies: CoverImageFamily._dependencies,
|
||||||
allTransitiveDependencies:
|
allTransitiveDependencies:
|
||||||
CoverImageFamily._allTransitiveDependencies,
|
CoverImageFamily._allTransitiveDependencies,
|
||||||
libraryItem: libraryItem,
|
itemId: itemId,
|
||||||
);
|
);
|
||||||
|
|
||||||
CoverImageProvider._internal(
|
CoverImageProvider._internal(
|
||||||
|
|
@ -106,17 +106,17 @@ class CoverImageProvider
|
||||||
required super.allTransitiveDependencies,
|
required super.allTransitiveDependencies,
|
||||||
required super.debugGetCreateSourceHash,
|
required super.debugGetCreateSourceHash,
|
||||||
required super.from,
|
required super.from,
|
||||||
required this.libraryItem,
|
required this.itemId,
|
||||||
}) : super.internal();
|
}) : super.internal();
|
||||||
|
|
||||||
final LibraryItem libraryItem;
|
final String itemId;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Stream<Uint8List> runNotifierBuild(
|
Stream<Uint8List> runNotifierBuild(
|
||||||
covariant CoverImage notifier,
|
covariant CoverImage notifier,
|
||||||
) {
|
) {
|
||||||
return notifier.build(
|
return notifier.build(
|
||||||
libraryItem,
|
itemId,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -125,13 +125,13 @@ class CoverImageProvider
|
||||||
return ProviderOverride(
|
return ProviderOverride(
|
||||||
origin: this,
|
origin: this,
|
||||||
override: CoverImageProvider._internal(
|
override: CoverImageProvider._internal(
|
||||||
() => create()..libraryItem = libraryItem,
|
() => create()..itemId = itemId,
|
||||||
from: from,
|
from: from,
|
||||||
name: null,
|
name: null,
|
||||||
dependencies: null,
|
dependencies: null,
|
||||||
allTransitiveDependencies: null,
|
allTransitiveDependencies: null,
|
||||||
debugGetCreateSourceHash: null,
|
debugGetCreateSourceHash: null,
|
||||||
libraryItem: libraryItem,
|
itemId: itemId,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -143,21 +143,21 @@ class CoverImageProvider
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) {
|
bool operator ==(Object other) {
|
||||||
return other is CoverImageProvider && other.libraryItem == libraryItem;
|
return other is CoverImageProvider && other.itemId == itemId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int get hashCode {
|
int get hashCode {
|
||||||
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
||||||
hash = _SystemHash.combine(hash, libraryItem.hashCode);
|
hash = _SystemHash.combine(hash, itemId.hashCode);
|
||||||
|
|
||||||
return _SystemHash.finish(hash);
|
return _SystemHash.finish(hash);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mixin CoverImageRef on StreamNotifierProviderRef<Uint8List> {
|
mixin CoverImageRef on StreamNotifierProviderRef<Uint8List> {
|
||||||
/// The parameter `libraryItem` of this provider.
|
/// The parameter `itemId` of this provider.
|
||||||
LibraryItem get libraryItem;
|
String get itemId;
|
||||||
}
|
}
|
||||||
|
|
||||||
class _CoverImageProviderElement
|
class _CoverImageProviderElement
|
||||||
|
|
@ -166,7 +166,7 @@ class _CoverImageProviderElement
|
||||||
_CoverImageProviderElement(super.provider);
|
_CoverImageProviderElement(super.provider);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
LibraryItem get libraryItem => (origin as CoverImageProvider).libraryItem;
|
String get itemId => (origin as CoverImageProvider).itemId;
|
||||||
}
|
}
|
||||||
// ignore_for_file: type=lint
|
// ignore_for_file: type=lint
|
||||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ part 'library_item_provider.g.dart';
|
||||||
final _logger = Logger('LibraryItemProvider');
|
final _logger = Logger('LibraryItemProvider');
|
||||||
|
|
||||||
/// provides the library item for the given id
|
/// provides the library item for the given id
|
||||||
@riverpod
|
@Riverpod(keepAlive: true)
|
||||||
class LibraryItem extends _$LibraryItem {
|
class LibraryItem extends _$LibraryItem {
|
||||||
@override
|
@override
|
||||||
Stream<shelfsdk.LibraryItemExpanded> build(String id) async* {
|
Stream<shelfsdk.LibraryItemExpanded> build(String id) async* {
|
||||||
|
|
@ -22,7 +22,7 @@ class LibraryItem extends _$LibraryItem {
|
||||||
_logger.fine('LibraryItemProvider fetching library item: $id');
|
_logger.fine('LibraryItemProvider fetching library item: $id');
|
||||||
|
|
||||||
// ! this is a mock delay
|
// ! this is a mock delay
|
||||||
// await Future.delayed(const Duration(seconds: 10));
|
// await Future.delayed(const Duration(seconds: 150));
|
||||||
|
|
||||||
// look for the item in the cache
|
// look for the item in the cache
|
||||||
final key = CacheKey.libraryItem(id);
|
final key = CacheKey.libraryItem(id);
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ part of 'library_item_provider.dart';
|
||||||
// RiverpodGenerator
|
// RiverpodGenerator
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
String _$libraryItemHash() => r'fa3f8309349c5b1b777f1bc919616e51c3f5b520';
|
String _$libraryItemHash() => r'a3cfa7f912e9498a70b5782899018b6964d6445c';
|
||||||
|
|
||||||
/// Copied from Dart SDK
|
/// Copied from Dart SDK
|
||||||
class _SystemHash {
|
class _SystemHash {
|
||||||
|
|
@ -30,7 +30,7 @@ class _SystemHash {
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class _$LibraryItem
|
abstract class _$LibraryItem
|
||||||
extends BuildlessAutoDisposeStreamNotifier<shelfsdk.LibraryItemExpanded> {
|
extends BuildlessStreamNotifier<shelfsdk.LibraryItemExpanded> {
|
||||||
late final String id;
|
late final String id;
|
||||||
|
|
||||||
Stream<shelfsdk.LibraryItemExpanded> build(
|
Stream<shelfsdk.LibraryItemExpanded> build(
|
||||||
|
|
@ -92,8 +92,8 @@ class LibraryItemFamily
|
||||||
/// provides the library item for the given id
|
/// provides the library item for the given id
|
||||||
///
|
///
|
||||||
/// Copied from [LibraryItem].
|
/// Copied from [LibraryItem].
|
||||||
class LibraryItemProvider extends AutoDisposeStreamNotifierProviderImpl<
|
class LibraryItemProvider extends StreamNotifierProviderImpl<LibraryItem,
|
||||||
LibraryItem, shelfsdk.LibraryItemExpanded> {
|
shelfsdk.LibraryItemExpanded> {
|
||||||
/// provides the library item for the given id
|
/// provides the library item for the given id
|
||||||
///
|
///
|
||||||
/// Copied from [LibraryItem].
|
/// Copied from [LibraryItem].
|
||||||
|
|
@ -151,8 +151,8 @@ class LibraryItemProvider extends AutoDisposeStreamNotifierProviderImpl<
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
AutoDisposeStreamNotifierProviderElement<LibraryItem,
|
StreamNotifierProviderElement<LibraryItem, shelfsdk.LibraryItemExpanded>
|
||||||
shelfsdk.LibraryItemExpanded> createElement() {
|
createElement() {
|
||||||
return _LibraryItemProviderElement(this);
|
return _LibraryItemProviderElement(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -171,14 +171,13 @@ class LibraryItemProvider extends AutoDisposeStreamNotifierProviderImpl<
|
||||||
}
|
}
|
||||||
|
|
||||||
mixin LibraryItemRef
|
mixin LibraryItemRef
|
||||||
on AutoDisposeStreamNotifierProviderRef<shelfsdk.LibraryItemExpanded> {
|
on StreamNotifierProviderRef<shelfsdk.LibraryItemExpanded> {
|
||||||
/// The parameter `id` of this provider.
|
/// The parameter `id` of this provider.
|
||||||
String get id;
|
String get id;
|
||||||
}
|
}
|
||||||
|
|
||||||
class _LibraryItemProviderElement
|
class _LibraryItemProviderElement extends StreamNotifierProviderElement<
|
||||||
extends AutoDisposeStreamNotifierProviderElement<LibraryItem,
|
LibraryItem, shelfsdk.LibraryItemExpanded> with LibraryItemRef {
|
||||||
shelfsdk.LibraryItemExpanded> with LibraryItemRef {
|
|
||||||
_LibraryItemProviderElement(super.provider);
|
_LibraryItemProviderElement(super.provider);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
|
||||||
|
|
@ -234,7 +234,7 @@ class BookSearchResultMini extends HookConsumerWidget {
|
||||||
final item = ref.watch(libraryItemProvider(book.libraryItemId)).valueOrNull;
|
final item = ref.watch(libraryItemProvider(book.libraryItemId)).valueOrNull;
|
||||||
final image = item == null
|
final image = item == null
|
||||||
? const AsyncValue.loading()
|
? const AsyncValue.loading()
|
||||||
: ref.watch(coverImageProvider(item));
|
: ref.watch(coverImageProvider(item.id));
|
||||||
return ListTile(
|
return ListTile(
|
||||||
leading: SizedBox(
|
leading: SizedBox(
|
||||||
width: 50,
|
width: 50,
|
||||||
|
|
|
||||||
|
|
@ -26,17 +26,19 @@ import 'package:vaani/shared/extensions/model_conversions.dart';
|
||||||
import 'package:vaani/shared/utils.dart';
|
import 'package:vaani/shared/utils.dart';
|
||||||
|
|
||||||
class LibraryItemActions extends HookConsumerWidget {
|
class LibraryItemActions extends HookConsumerWidget {
|
||||||
LibraryItemActions({
|
const LibraryItemActions({
|
||||||
super.key,
|
super.key,
|
||||||
required this.item,
|
required this.id,
|
||||||
}) {
|
});
|
||||||
book = item.media.asBookExpanded;
|
|
||||||
}
|
final String id;
|
||||||
|
|
||||||
final shelfsdk.LibraryItemExpanded item;
|
|
||||||
late final shelfsdk.BookExpanded book;
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final item = ref.watch(libraryItemProvider(id)).valueOrNull;
|
||||||
|
if (item == null) {
|
||||||
|
return const SizedBox.shrink();
|
||||||
|
}
|
||||||
final downloadHistory = ref.watch(downloadHistoryProvider(group: item.id));
|
final downloadHistory = ref.watch(downloadHistoryProvider(group: item.id));
|
||||||
final apiSettings = ref.watch(apiSettingsProvider);
|
final apiSettings = ref.watch(apiSettingsProvider);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
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/image_provider.dart';
|
import 'package:vaani/api/image_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/features/item_viewer/view/library_item_page.dart';
|
import 'package:vaani/features/item_viewer/view/library_item_page.dart';
|
||||||
import 'package:vaani/features/player/providers/audiobook_player.dart';
|
import 'package:vaani/features/player/providers/audiobook_player.dart';
|
||||||
|
|
@ -14,125 +15,120 @@ import 'package:vaani/settings/app_settings_provider.dart';
|
||||||
import 'package:vaani/shared/extensions/duration_format.dart';
|
import 'package:vaani/shared/extensions/duration_format.dart';
|
||||||
import 'package:vaani/shared/extensions/model_conversions.dart';
|
import 'package:vaani/shared/extensions/model_conversions.dart';
|
||||||
import 'package:vaani/shared/widgets/shelves/book_shelf.dart';
|
import 'package:vaani/shared/widgets/shelves/book_shelf.dart';
|
||||||
|
import 'package:vaani/theme/theme_from_cover_provider.dart';
|
||||||
|
|
||||||
class LibraryItemHeroSection extends HookConsumerWidget {
|
class LibraryItemHeroSection extends HookConsumerWidget {
|
||||||
const LibraryItemHeroSection({
|
const LibraryItemHeroSection({
|
||||||
super.key,
|
super.key,
|
||||||
required this.itemId,
|
required this.itemId,
|
||||||
required this.extraMap,
|
required this.extraMap,
|
||||||
required this.providedCacheImage,
|
|
||||||
required this.item,
|
|
||||||
required this.itemBookMetadata,
|
|
||||||
required this.bookDetailsCached,
|
|
||||||
required this.coverColorScheme,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
final String itemId;
|
final String itemId;
|
||||||
final LibraryItemExtras? extraMap;
|
final LibraryItemExtras? extraMap;
|
||||||
final Image? providedCacheImage;
|
|
||||||
final AsyncValue<shelfsdk.LibraryItemExpanded> item;
|
|
||||||
final shelfsdk.BookMetadataExpanded? itemBookMetadata;
|
|
||||||
final shelfsdk.BookMinified? bookDetailsCached;
|
|
||||||
final AsyncValue<ColorScheme?> coverColorScheme;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
return SliverToBoxAdapter(
|
return SliverToBoxAdapter(
|
||||||
child: LayoutBuilder(
|
child: Row(
|
||||||
builder: (context, constraints) {
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
return Container(
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
child: Row(
|
children: [
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
// book cover
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
LayoutBuilder(
|
||||||
children: [
|
builder: (context, constraints) {
|
||||||
// book cover
|
return SizedBox(
|
||||||
LayoutBuilder(
|
width: calculateWidth(context, constraints),
|
||||||
builder: (context, constraints) {
|
child: Column(
|
||||||
return SizedBox(
|
children: [
|
||||||
width: calculateWidth(context, constraints),
|
Hero(
|
||||||
child: Column(
|
tag: HeroTagPrefixes.bookCover +
|
||||||
children: [
|
itemId +
|
||||||
Hero(
|
(extraMap?.heroTagSuffix ?? ''),
|
||||||
tag: HeroTagPrefixes.bookCover +
|
child: ClipRRect(
|
||||||
itemId +
|
borderRadius: BorderRadius.circular(16),
|
||||||
(extraMap?.heroTagSuffix ?? ''),
|
child: _BookCover(
|
||||||
child: ClipRRect(
|
itemId: itemId,
|
||||||
borderRadius: BorderRadius.circular(16),
|
),
|
||||||
child: _BookCover(
|
|
||||||
itemId: itemId,
|
|
||||||
extraMap: extraMap,
|
|
||||||
providedCacheImage: providedCacheImage,
|
|
||||||
coverColorScheme: coverColorScheme.valueOrNull,
|
|
||||||
item: item,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
// a progress bar if available
|
|
||||||
item.when(
|
|
||||||
data: (libraryItem) {
|
|
||||||
return Padding(
|
|
||||||
padding: const EdgeInsets.only(
|
|
||||||
top: 8.0,
|
|
||||||
right: 8.0,
|
|
||||||
left: 8.0,
|
|
||||||
),
|
|
||||||
child: _LibraryItemProgressIndicator(
|
|
||||||
libraryItem: libraryItem,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
loading: () => const SizedBox.shrink(),
|
|
||||||
error: (error, stack) => const SizedBox.shrink(),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
// book details
|
|
||||||
Expanded(
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 8),
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
_BookTitle(
|
|
||||||
extraMap: extraMap,
|
|
||||||
itemBookMetadata: itemBookMetadata,
|
|
||||||
bookDetailsCached: bookDetailsCached,
|
|
||||||
),
|
|
||||||
Container(
|
|
||||||
margin: const EdgeInsets.symmetric(vertical: 16),
|
|
||||||
child: Column(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
// authors info if available
|
|
||||||
_BookAuthors(
|
|
||||||
itemBookMetadata: itemBookMetadata,
|
|
||||||
bookDetailsCached: bookDetailsCached,
|
|
||||||
),
|
|
||||||
// narrators info if available
|
|
||||||
_BookNarrators(
|
|
||||||
itemBookMetadata: itemBookMetadata,
|
|
||||||
bookDetailsCached: bookDetailsCached,
|
|
||||||
),
|
|
||||||
// series info if available
|
|
||||||
_BookSeries(
|
|
||||||
itemBookMetadata: itemBookMetadata,
|
|
||||||
bookDetailsCached: bookDetailsCached,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
),
|
// a progress bar
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(
|
||||||
|
top: 8.0,
|
||||||
|
right: 8.0,
|
||||||
|
left: 8.0,
|
||||||
|
),
|
||||||
|
child: _LibraryItemProgressIndicator(
|
||||||
|
id: itemId,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
],
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
// book details
|
||||||
|
_BookDetails(id: itemId, extraMap: extraMap),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _BookDetails extends HookConsumerWidget {
|
||||||
|
const _BookDetails({
|
||||||
|
super.key,
|
||||||
|
required this.id,
|
||||||
|
this.extraMap,
|
||||||
|
});
|
||||||
|
|
||||||
|
final String id;
|
||||||
|
final LibraryItemExtras? extraMap;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final itemFromApi = ref.watch(libraryItemProvider(id));
|
||||||
|
|
||||||
|
final itemBookMetadata =
|
||||||
|
itemFromApi.valueOrNull?.media.metadata.asBookMetadataExpanded;
|
||||||
|
|
||||||
|
return Expanded(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 8),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
_BookTitle(
|
||||||
|
extraMap: extraMap,
|
||||||
|
itemBookMetadata: itemBookMetadata,
|
||||||
),
|
),
|
||||||
);
|
Container(
|
||||||
},
|
margin: const EdgeInsets.symmetric(vertical: 16),
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
// authors info if available
|
||||||
|
_BookAuthors(
|
||||||
|
itemBookMetadata: itemBookMetadata,
|
||||||
|
bookDetailsCached: extraMap?.book,
|
||||||
|
),
|
||||||
|
// narrators info if available
|
||||||
|
_BookNarrators(
|
||||||
|
itemBookMetadata: itemBookMetadata,
|
||||||
|
bookDetailsCached: extraMap?.book,
|
||||||
|
),
|
||||||
|
// series info if available
|
||||||
|
_BookSeries(
|
||||||
|
itemBookMetadata: itemBookMetadata,
|
||||||
|
bookDetailsCached: extraMap?.book,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -141,14 +137,19 @@ class LibraryItemHeroSection extends HookConsumerWidget {
|
||||||
class _LibraryItemProgressIndicator extends HookConsumerWidget {
|
class _LibraryItemProgressIndicator extends HookConsumerWidget {
|
||||||
const _LibraryItemProgressIndicator({
|
const _LibraryItemProgressIndicator({
|
||||||
super.key,
|
super.key,
|
||||||
required this.libraryItem,
|
required this.id,
|
||||||
});
|
});
|
||||||
|
|
||||||
final shelfsdk.LibraryItemExpanded libraryItem;
|
final String id;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final player = ref.watch(audiobookPlayerProvider);
|
final player = ref.watch(audiobookPlayerProvider);
|
||||||
|
final libraryItem = ref.watch(libraryItemProvider(id)).valueOrNull;
|
||||||
|
if (libraryItem == null) {
|
||||||
|
return const SizedBox.shrink();
|
||||||
|
}
|
||||||
|
|
||||||
final mediaProgress = libraryItem.userMediaProgress;
|
final mediaProgress = libraryItem.userMediaProgress;
|
||||||
if (mediaProgress == null && player.book?.libraryItemId != libraryItem.id) {
|
if (mediaProgress == null && player.book?.libraryItemId != libraryItem.id) {
|
||||||
return const SizedBox.shrink();
|
return const SizedBox.shrink();
|
||||||
|
|
@ -188,6 +189,8 @@ class _LibraryItemProgressIndicator extends HookConsumerWidget {
|
||||||
LinearProgressIndicator(
|
LinearProgressIndicator(
|
||||||
value: progress.clamp(0.03, 1),
|
value: progress.clamp(0.03, 1),
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
semanticsLabel: 'Book progress',
|
||||||
|
semanticsValue: '${progressInPercent.toStringAsFixed(2)}%',
|
||||||
),
|
),
|
||||||
const SizedBox.square(
|
const SizedBox.square(
|
||||||
dimension: 4.0,
|
dimension: 4.0,
|
||||||
|
|
@ -341,24 +344,30 @@ class _BookCover extends HookConsumerWidget {
|
||||||
const _BookCover({
|
const _BookCover({
|
||||||
super.key,
|
super.key,
|
||||||
required this.itemId,
|
required this.itemId,
|
||||||
required this.extraMap,
|
|
||||||
required this.providedCacheImage,
|
|
||||||
required this.item,
|
|
||||||
this.coverColorScheme,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
final String itemId;
|
final String itemId;
|
||||||
final LibraryItemExtras? extraMap;
|
|
||||||
final Image? providedCacheImage;
|
|
||||||
final AsyncValue<shelfsdk.LibraryItemExpanded> item;
|
|
||||||
final ColorScheme? coverColorScheme;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final coverImage = ref.watch(coverImageProvider(itemId));
|
||||||
final themeData = Theme.of(context);
|
final themeData = Theme.of(context);
|
||||||
|
// final item = ref.watch(libraryItemProvider(itemId));
|
||||||
final useMaterialThemeOnItemPage =
|
final useMaterialThemeOnItemPage =
|
||||||
ref.watch(appSettingsProvider).themeSettings.useMaterialThemeOnItemPage;
|
ref.watch(appSettingsProvider).themeSettings.useMaterialThemeOnItemPage;
|
||||||
|
|
||||||
|
ColorScheme? coverColorScheme;
|
||||||
|
if (useMaterialThemeOnItemPage) {
|
||||||
|
coverColorScheme = ref
|
||||||
|
.watch(
|
||||||
|
themeOfLibraryItemProvider(
|
||||||
|
itemId,
|
||||||
|
brightness: Theme.of(context).brightness,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.valueOrNull;
|
||||||
|
}
|
||||||
|
|
||||||
return ThemeSwitcher(
|
return ThemeSwitcher(
|
||||||
builder: (context) {
|
builder: (context) {
|
||||||
// change theme after 2 seconds
|
// change theme after 2 seconds
|
||||||
|
|
@ -368,7 +377,7 @@ class _BookCover extends HookConsumerWidget {
|
||||||
ThemeSwitcher.of(context).changeTheme(
|
ThemeSwitcher.of(context).changeTheme(
|
||||||
theme: coverColorScheme != null
|
theme: coverColorScheme != null
|
||||||
? ThemeData.from(
|
? ThemeData.from(
|
||||||
colorScheme: coverColorScheme!,
|
colorScheme: coverColorScheme,
|
||||||
textTheme: themeData.textTheme,
|
textTheme: themeData.textTheme,
|
||||||
)
|
)
|
||||||
: themeData,
|
: themeData,
|
||||||
|
|
@ -378,42 +387,27 @@ class _BookCover extends HookConsumerWidget {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return providedCacheImage ??
|
return coverImage.when(
|
||||||
item.when(
|
data: (image) {
|
||||||
data: (libraryItem) {
|
// return const BookCoverSkeleton();
|
||||||
final coverImage = ref.watch(coverImageProvider(libraryItem));
|
if (image.isEmpty) {
|
||||||
return Stack(
|
return const Icon(Icons.error);
|
||||||
children: [
|
}
|
||||||
coverImage.when(
|
|
||||||
data: (image) {
|
return Image.memory(
|
||||||
// return const BookCoverSkeleton();
|
image,
|
||||||
if (image.isEmpty) {
|
fit: BoxFit.cover,
|
||||||
return const Icon(Icons.error);
|
|
||||||
}
|
|
||||||
// cover 80% of parent height
|
|
||||||
return Image.memory(
|
|
||||||
image,
|
|
||||||
fit: BoxFit.cover,
|
|
||||||
// cacheWidth: (height *
|
|
||||||
// MediaQuery.of(context).devicePixelRatio)
|
|
||||||
// .round(),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
loading: () {
|
|
||||||
return const Center(
|
|
||||||
child: BookCoverSkeleton(),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
error: (error, stack) {
|
|
||||||
return const Icon(Icons.error);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
},
|
|
||||||
error: (error, stack) => const Icon(Icons.error),
|
|
||||||
loading: () => const Center(child: BookCoverSkeleton()),
|
|
||||||
);
|
);
|
||||||
|
},
|
||||||
|
loading: () {
|
||||||
|
return const Center(
|
||||||
|
child: BookCoverSkeleton(),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
error: (error, stack) {
|
||||||
|
return const Center(child: Icon(Icons.error));
|
||||||
|
},
|
||||||
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -424,12 +418,10 @@ class _BookTitle extends StatelessWidget {
|
||||||
super.key,
|
super.key,
|
||||||
required this.extraMap,
|
required this.extraMap,
|
||||||
required this.itemBookMetadata,
|
required this.itemBookMetadata,
|
||||||
required this.bookDetailsCached,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
final LibraryItemExtras? extraMap;
|
final LibraryItemExtras? extraMap;
|
||||||
final shelfsdk.BookMetadataExpanded? itemBookMetadata;
|
final shelfsdk.BookMetadataExpanded? itemBookMetadata;
|
||||||
final shelfsdk.BookMinified? bookDetailsCached;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
|
@ -449,7 +441,7 @@ class _BookTitle extends StatelessWidget {
|
||||||
// pauseBetween: 150.ms,
|
// pauseBetween: 150.ms,
|
||||||
// numberOfReps: 3,
|
// numberOfReps: 3,
|
||||||
style: themeData.textTheme.headlineLarge,
|
style: themeData.textTheme.headlineLarge,
|
||||||
itemBookMetadata?.title ?? bookDetailsCached?.metadata.title ?? '',
|
itemBookMetadata?.title ?? extraMap?.book?.metadata.title ?? '',
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
// subtitle if available
|
// subtitle if available
|
||||||
|
|
@ -482,7 +474,7 @@ class _BookAuthors extends StatelessWidget {
|
||||||
String generateAuthorsString() {
|
String generateAuthorsString() {
|
||||||
final authors = (itemBookMetadata)?.authors ?? [];
|
final authors = (itemBookMetadata)?.authors ?? [];
|
||||||
if (authors.isEmpty) {
|
if (authors.isEmpty) {
|
||||||
return (bookDetailsCached?.metadata as shelfsdk.BookMetadataMinified?)
|
return (bookDetailsCached?.metadata.asBookMetadataMinified)
|
||||||
?.authorName ??
|
?.authorName ??
|
||||||
'';
|
'';
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,65 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:shelfsdk/audiobookshelf_api.dart' as shelfsdk;
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:vaani/api/library_item_provider.dart';
|
||||||
|
import 'package:vaani/shared/extensions/model_conversions.dart';
|
||||||
|
|
||||||
class LibraryItemMetadata extends StatelessWidget {
|
class LibraryItemMetadata extends HookConsumerWidget {
|
||||||
const LibraryItemMetadata({
|
const LibraryItemMetadata({
|
||||||
super.key,
|
super.key,
|
||||||
required this.item,
|
required this.id,
|
||||||
this.itemBookMetadata,
|
|
||||||
this.bookDetailsCached,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
final shelfsdk.LibraryItemExpanded item;
|
final String id;
|
||||||
final shelfsdk.BookMetadataExpanded? itemBookMetadata;
|
|
||||||
final shelfsdk.BookMinified? bookDetailsCached;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final item = ref.watch(libraryItemProvider(id)).valueOrNull;
|
||||||
|
|
||||||
|
/// formats the duration of the book as `10h 30m`
|
||||||
|
///
|
||||||
|
/// will add up all the durations of the audio files first
|
||||||
|
/// then convert them to the given format
|
||||||
|
String? getDurationFormatted() {
|
||||||
|
final book = (item?.media.asBookExpanded);
|
||||||
|
if (book == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
final duration = book.audioFiles
|
||||||
|
.map((e) => e.duration)
|
||||||
|
.reduce((value, element) => value + element);
|
||||||
|
final hours = duration.inHours;
|
||||||
|
final minutes = duration.inMinutes.remainder(60);
|
||||||
|
return '${hours}h ${minutes}m';
|
||||||
|
}
|
||||||
|
|
||||||
|
/// will return the size of the book in MB
|
||||||
|
///
|
||||||
|
/// will add up all the sizes of the audio files first
|
||||||
|
/// then convert them to MB
|
||||||
|
String? getSizeFormatted() {
|
||||||
|
final book = (item?.media.asBookExpanded);
|
||||||
|
if (book == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
final size = book.audioFiles
|
||||||
|
.map((e) => e.metadata.size)
|
||||||
|
.reduce((value, element) => value + element);
|
||||||
|
return '${size / 1024 ~/ 1024} MB';
|
||||||
|
}
|
||||||
|
|
||||||
|
/// will return the codec and bitrate of the book
|
||||||
|
String? getCodecAndBitrate() {
|
||||||
|
final book = (item?.media.asBookExpanded);
|
||||||
|
if (book == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
final codec = book.audioFiles.first.codec.toUpperCase();
|
||||||
|
// final bitrate = book.audioFiles.first.bitRate;
|
||||||
|
return codec;
|
||||||
|
}
|
||||||
|
|
||||||
|
final itemBookMetadata = item?.media.metadata.asBookMetadataExpanded;
|
||||||
|
|
||||||
final children = [
|
final children = [
|
||||||
// duration of the book
|
// duration of the book
|
||||||
_MetadataItem(
|
_MetadataItem(
|
||||||
|
|
@ -59,49 +104,6 @@ class LibraryItemMetadata extends StatelessWidget {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// formats the duration of the book as `10h 30m`
|
|
||||||
///
|
|
||||||
/// will add up all the durations of the audio files first
|
|
||||||
/// then convert them to the given format
|
|
||||||
String? getDurationFormatted() {
|
|
||||||
final book = (item.media as shelfsdk.BookExpanded?);
|
|
||||||
if (book == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
final duration = book.audioFiles
|
|
||||||
.map((e) => e.duration)
|
|
||||||
.reduce((value, element) => value + element);
|
|
||||||
final hours = duration.inHours;
|
|
||||||
final minutes = duration.inMinutes.remainder(60);
|
|
||||||
return '${hours}h ${minutes}m';
|
|
||||||
}
|
|
||||||
|
|
||||||
/// will return the size of the book in MB
|
|
||||||
///
|
|
||||||
/// will add up all the sizes of the audio files first
|
|
||||||
/// then convert them to MB
|
|
||||||
String? getSizeFormatted() {
|
|
||||||
final book = (item.media as shelfsdk.BookExpanded?);
|
|
||||||
if (book == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
final size = book.audioFiles
|
|
||||||
.map((e) => e.metadata.size)
|
|
||||||
.reduce((value, element) => value + element);
|
|
||||||
return '${size / 1024 ~/ 1024} MB';
|
|
||||||
}
|
|
||||||
|
|
||||||
/// will return the codec and bitrate of the book
|
|
||||||
String? getCodecAndBitrate() {
|
|
||||||
final book = (item.media as shelfsdk.BookExpanded?);
|
|
||||||
if (book == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
final codec = book.audioFiles.first.codec.toUpperCase();
|
|
||||||
// final bitrate = book.audioFiles.first.bitRate;
|
|
||||||
return codec;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// key-value pair to display as column
|
/// key-value pair to display as column
|
||||||
|
|
|
||||||
|
|
@ -8,10 +8,7 @@ import 'package:vaani/api/library_item_provider.dart';
|
||||||
import 'package:vaani/features/item_viewer/view/library_item_sliver_app_bar.dart';
|
import 'package:vaani/features/item_viewer/view/library_item_sliver_app_bar.dart';
|
||||||
import 'package:vaani/features/player/providers/player_form.dart';
|
import 'package:vaani/features/player/providers/player_form.dart';
|
||||||
import 'package:vaani/router/models/library_item_extras.dart';
|
import 'package:vaani/router/models/library_item_extras.dart';
|
||||||
import 'package:vaani/settings/app_settings_provider.dart';
|
|
||||||
import 'package:vaani/shared/extensions/model_conversions.dart';
|
|
||||||
import 'package:vaani/shared/widgets/expandable_description.dart';
|
import 'package:vaani/shared/widgets/expandable_description.dart';
|
||||||
import 'package:vaani/theme/theme_from_cover_provider.dart';
|
|
||||||
|
|
||||||
import 'library_item_actions.dart';
|
import 'library_item_actions.dart';
|
||||||
import 'library_item_hero_section.dart';
|
import 'library_item_hero_section.dart';
|
||||||
|
|
@ -28,33 +25,9 @@ class LibraryItemPage extends HookConsumerWidget {
|
||||||
final Object? extra;
|
final Object? extra;
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final extraMap =
|
final additionalItemData =
|
||||||
extra is LibraryItemExtras ? extra as LibraryItemExtras : null;
|
extra is LibraryItemExtras ? extra as LibraryItemExtras : null;
|
||||||
final bookDetailsCached = extraMap?.book;
|
|
||||||
final providedCacheImage = extraMap?.coverImage != null
|
|
||||||
? Image.memory(extraMap!.coverImage!)
|
|
||||||
: null;
|
|
||||||
|
|
||||||
final itemFromApi = ref.watch(libraryItemProvider(itemId));
|
|
||||||
|
|
||||||
var itemBookMetadata =
|
|
||||||
itemFromApi.valueOrNull?.media.metadata.asBookMetadataExpanded;
|
|
||||||
|
|
||||||
final useMaterialThemeOnItemPage =
|
|
||||||
ref.watch(appSettingsProvider).themeSettings.useMaterialThemeOnItemPage;
|
|
||||||
AsyncValue<ColorScheme?> coverColorScheme = const AsyncValue.loading();
|
|
||||||
if (useMaterialThemeOnItemPage) {
|
|
||||||
coverColorScheme = ref.watch(
|
|
||||||
themeOfLibraryItemProvider(
|
|
||||||
itemFromApi.valueOrNull,
|
|
||||||
brightness: Theme.of(context).brightness,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
debugPrint('ColorScheme: ${coverColorScheme.valueOrNull}');
|
|
||||||
} else {
|
|
||||||
debugPrint('useMaterialThemeOnItemPage is false');
|
|
||||||
// AsyncValue<ColorScheme?> coverColorScheme = const AsyncValue.loading();
|
|
||||||
}
|
|
||||||
return ThemeProvider(
|
return ThemeProvider(
|
||||||
initTheme: Theme.of(context),
|
initTheme: Theme.of(context),
|
||||||
duration: 200.ms,
|
duration: 200.ms,
|
||||||
|
|
@ -67,40 +40,20 @@ class LibraryItemPage extends HookConsumerWidget {
|
||||||
padding: const EdgeInsets.all(8),
|
padding: const EdgeInsets.all(8),
|
||||||
sliver: LibraryItemHeroSection(
|
sliver: LibraryItemHeroSection(
|
||||||
itemId: itemId,
|
itemId: itemId,
|
||||||
extraMap: extraMap,
|
extraMap: additionalItemData,
|
||||||
providedCacheImage: providedCacheImage,
|
|
||||||
item: itemFromApi,
|
|
||||||
itemBookMetadata: itemBookMetadata,
|
|
||||||
bookDetailsCached: bookDetailsCached,
|
|
||||||
coverColorScheme: coverColorScheme,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
// a horizontal display with dividers of metadata
|
// a horizontal display with dividers of metadata
|
||||||
SliverToBoxAdapter(
|
SliverToBoxAdapter(
|
||||||
child: itemFromApi.valueOrNull != null
|
child: LibraryItemMetadata(id: itemId),
|
||||||
? LibraryItemMetadata(
|
|
||||||
item: itemFromApi.valueOrNull!,
|
|
||||||
itemBookMetadata: itemBookMetadata,
|
|
||||||
bookDetailsCached: bookDetailsCached,
|
|
||||||
)
|
|
||||||
: const SizedBox.shrink(),
|
|
||||||
),
|
),
|
||||||
// a row of actions like play, download, share, etc
|
// a row of actions like play, download, share, etc
|
||||||
SliverToBoxAdapter(
|
SliverToBoxAdapter(
|
||||||
child: itemFromApi.valueOrNull != null
|
child: LibraryItemActions(id: itemId),
|
||||||
? LibraryItemActions(item: itemFromApi.valueOrNull!)
|
|
||||||
: const SizedBox.shrink(),
|
|
||||||
),
|
),
|
||||||
// a expandable section for book description
|
// a expandable section for book description
|
||||||
SliverToBoxAdapter(
|
SliverToBoxAdapter(
|
||||||
child:
|
child: LibraryItemDescription(id: itemId),
|
||||||
itemFromApi.valueOrNull?.media.metadata.description != null
|
|
||||||
? ExpandableDescription(
|
|
||||||
title: 'About the Book',
|
|
||||||
content: itemFromApi
|
|
||||||
.valueOrNull!.media.metadata.description!,
|
|
||||||
)
|
|
||||||
: const SizedBox.shrink(),
|
|
||||||
),
|
),
|
||||||
// a padding at the bottom to make sure the last item is not hidden by mini player
|
// a padding at the bottom to make sure the last item is not hidden by mini player
|
||||||
const SliverToBoxAdapter(
|
const SliverToBoxAdapter(
|
||||||
|
|
@ -114,6 +67,26 @@ class LibraryItemPage extends HookConsumerWidget {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class LibraryItemDescription extends HookConsumerWidget {
|
||||||
|
const LibraryItemDescription({
|
||||||
|
super.key,
|
||||||
|
required this.id,
|
||||||
|
});
|
||||||
|
|
||||||
|
final String id;
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final item = ref.watch(libraryItemProvider(id)).valueOrNull;
|
||||||
|
if (item == null) {
|
||||||
|
return const SizedBox();
|
||||||
|
}
|
||||||
|
return ExpandableDescription(
|
||||||
|
title: 'About the Book',
|
||||||
|
content: item.media.metadata.description ?? 'Sorry, no description found',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Calculate the width of the book cover based on the screen size
|
/// Calculate the width of the book cover based on the screen size
|
||||||
double calculateWidth(
|
double calculateWidth(
|
||||||
BuildContext context,
|
BuildContext context,
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ class AudiobookPlayer extends HookConsumerWidget {
|
||||||
final player = ref.watch(audiobookPlayerProvider);
|
final player = ref.watch(audiobookPlayerProvider);
|
||||||
final imageOfItemBeingPlayed = itemBeingPlayed.valueOrNull != null
|
final imageOfItemBeingPlayed = itemBeingPlayed.valueOrNull != null
|
||||||
? ref.watch(
|
? ref.watch(
|
||||||
coverImageProvider(itemBeingPlayed.valueOrNull!),
|
coverImageProvider(itemBeingPlayed.valueOrNull!.id),
|
||||||
)
|
)
|
||||||
: null;
|
: null;
|
||||||
final imgWidget = imageOfItemBeingPlayed?.valueOrNull != null
|
final imgWidget = imageOfItemBeingPlayed?.valueOrNull != null
|
||||||
|
|
@ -63,7 +63,7 @@ class AudiobookPlayer extends HookConsumerWidget {
|
||||||
// theme from image
|
// theme from image
|
||||||
final imageTheme = ref.watch(
|
final imageTheme = ref.watch(
|
||||||
themeOfLibraryItemProvider(
|
themeOfLibraryItemProvider(
|
||||||
itemBeingPlayed.valueOrNull,
|
itemBeingPlayed.valueOrNull?.id,
|
||||||
brightness: Theme.of(context).brightness,
|
brightness: Theme.of(context).brightness,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,5 @@
|
||||||
// a freezed class to store the settings of the app
|
// a freezed class to store the settings of the app
|
||||||
|
|
||||||
import 'dart:typed_data';
|
|
||||||
|
|
||||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||||
import 'package:shelfsdk/audiobookshelf_api.dart';
|
import 'package:shelfsdk/audiobookshelf_api.dart';
|
||||||
|
|
||||||
|
|
@ -17,7 +15,6 @@ class LibraryItemExtras with _$LibraryItemExtras {
|
||||||
const factory LibraryItemExtras({
|
const factory LibraryItemExtras({
|
||||||
BookMinified? book,
|
BookMinified? book,
|
||||||
@Default('') String heroTagSuffix,
|
@Default('') String heroTagSuffix,
|
||||||
Uint8List? coverImage,
|
|
||||||
}) = _LibraryItemExtras;
|
}) = _LibraryItemExtras;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,6 @@ final _privateConstructorUsedError = UnsupportedError(
|
||||||
mixin _$LibraryItemExtras {
|
mixin _$LibraryItemExtras {
|
||||||
BookMinified? get book => throw _privateConstructorUsedError;
|
BookMinified? get book => throw _privateConstructorUsedError;
|
||||||
String get heroTagSuffix => throw _privateConstructorUsedError;
|
String get heroTagSuffix => throw _privateConstructorUsedError;
|
||||||
Uint8List? get coverImage => throw _privateConstructorUsedError;
|
|
||||||
|
|
||||||
/// Create a copy of LibraryItemExtras
|
/// Create a copy of LibraryItemExtras
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
|
@ -33,7 +32,7 @@ abstract class $LibraryItemExtrasCopyWith<$Res> {
|
||||||
LibraryItemExtras value, $Res Function(LibraryItemExtras) then) =
|
LibraryItemExtras value, $Res Function(LibraryItemExtras) then) =
|
||||||
_$LibraryItemExtrasCopyWithImpl<$Res, LibraryItemExtras>;
|
_$LibraryItemExtrasCopyWithImpl<$Res, LibraryItemExtras>;
|
||||||
@useResult
|
@useResult
|
||||||
$Res call({BookMinified? book, String heroTagSuffix, Uint8List? coverImage});
|
$Res call({BookMinified? book, String heroTagSuffix});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @nodoc
|
/// @nodoc
|
||||||
|
|
@ -53,7 +52,6 @@ class _$LibraryItemExtrasCopyWithImpl<$Res, $Val extends LibraryItemExtras>
|
||||||
$Res call({
|
$Res call({
|
||||||
Object? book = freezed,
|
Object? book = freezed,
|
||||||
Object? heroTagSuffix = null,
|
Object? heroTagSuffix = null,
|
||||||
Object? coverImage = freezed,
|
|
||||||
}) {
|
}) {
|
||||||
return _then(_value.copyWith(
|
return _then(_value.copyWith(
|
||||||
book: freezed == book
|
book: freezed == book
|
||||||
|
|
@ -64,10 +62,6 @@ class _$LibraryItemExtrasCopyWithImpl<$Res, $Val extends LibraryItemExtras>
|
||||||
? _value.heroTagSuffix
|
? _value.heroTagSuffix
|
||||||
: heroTagSuffix // ignore: cast_nullable_to_non_nullable
|
: heroTagSuffix // ignore: cast_nullable_to_non_nullable
|
||||||
as String,
|
as String,
|
||||||
coverImage: freezed == coverImage
|
|
||||||
? _value.coverImage
|
|
||||||
: coverImage // ignore: cast_nullable_to_non_nullable
|
|
||||||
as Uint8List?,
|
|
||||||
) as $Val);
|
) as $Val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -80,7 +74,7 @@ abstract class _$$LibraryItemExtrasImplCopyWith<$Res>
|
||||||
__$$LibraryItemExtrasImplCopyWithImpl<$Res>;
|
__$$LibraryItemExtrasImplCopyWithImpl<$Res>;
|
||||||
@override
|
@override
|
||||||
@useResult
|
@useResult
|
||||||
$Res call({BookMinified? book, String heroTagSuffix, Uint8List? coverImage});
|
$Res call({BookMinified? book, String heroTagSuffix});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @nodoc
|
/// @nodoc
|
||||||
|
|
@ -98,7 +92,6 @@ class __$$LibraryItemExtrasImplCopyWithImpl<$Res>
|
||||||
$Res call({
|
$Res call({
|
||||||
Object? book = freezed,
|
Object? book = freezed,
|
||||||
Object? heroTagSuffix = null,
|
Object? heroTagSuffix = null,
|
||||||
Object? coverImage = freezed,
|
|
||||||
}) {
|
}) {
|
||||||
return _then(_$LibraryItemExtrasImpl(
|
return _then(_$LibraryItemExtrasImpl(
|
||||||
book: freezed == book
|
book: freezed == book
|
||||||
|
|
@ -109,10 +102,6 @@ class __$$LibraryItemExtrasImplCopyWithImpl<$Res>
|
||||||
? _value.heroTagSuffix
|
? _value.heroTagSuffix
|
||||||
: heroTagSuffix // ignore: cast_nullable_to_non_nullable
|
: heroTagSuffix // ignore: cast_nullable_to_non_nullable
|
||||||
as String,
|
as String,
|
||||||
coverImage: freezed == coverImage
|
|
||||||
? _value.coverImage
|
|
||||||
: coverImage // ignore: cast_nullable_to_non_nullable
|
|
||||||
as Uint8List?,
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -120,20 +109,17 @@ class __$$LibraryItemExtrasImplCopyWithImpl<$Res>
|
||||||
/// @nodoc
|
/// @nodoc
|
||||||
|
|
||||||
class _$LibraryItemExtrasImpl implements _LibraryItemExtras {
|
class _$LibraryItemExtrasImpl implements _LibraryItemExtras {
|
||||||
const _$LibraryItemExtrasImpl(
|
const _$LibraryItemExtrasImpl({this.book, this.heroTagSuffix = ''});
|
||||||
{this.book, this.heroTagSuffix = '', this.coverImage});
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
final BookMinified? book;
|
final BookMinified? book;
|
||||||
@override
|
@override
|
||||||
@JsonKey()
|
@JsonKey()
|
||||||
final String heroTagSuffix;
|
final String heroTagSuffix;
|
||||||
@override
|
|
||||||
final Uint8List? coverImage;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return 'LibraryItemExtras(book: $book, heroTagSuffix: $heroTagSuffix, coverImage: $coverImage)';
|
return 'LibraryItemExtras(book: $book, heroTagSuffix: $heroTagSuffix)';
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
@ -143,14 +129,11 @@ class _$LibraryItemExtrasImpl implements _LibraryItemExtras {
|
||||||
other is _$LibraryItemExtrasImpl &&
|
other is _$LibraryItemExtrasImpl &&
|
||||||
(identical(other.book, book) || other.book == book) &&
|
(identical(other.book, book) || other.book == book) &&
|
||||||
(identical(other.heroTagSuffix, heroTagSuffix) ||
|
(identical(other.heroTagSuffix, heroTagSuffix) ||
|
||||||
other.heroTagSuffix == heroTagSuffix) &&
|
other.heroTagSuffix == heroTagSuffix));
|
||||||
const DeepCollectionEquality()
|
|
||||||
.equals(other.coverImage, coverImage));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int get hashCode => Object.hash(runtimeType, book, heroTagSuffix,
|
int get hashCode => Object.hash(runtimeType, book, heroTagSuffix);
|
||||||
const DeepCollectionEquality().hash(coverImage));
|
|
||||||
|
|
||||||
/// Create a copy of LibraryItemExtras
|
/// Create a copy of LibraryItemExtras
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
|
@ -165,15 +148,12 @@ class _$LibraryItemExtrasImpl implements _LibraryItemExtras {
|
||||||
abstract class _LibraryItemExtras implements LibraryItemExtras {
|
abstract class _LibraryItemExtras implements LibraryItemExtras {
|
||||||
const factory _LibraryItemExtras(
|
const factory _LibraryItemExtras(
|
||||||
{final BookMinified? book,
|
{final BookMinified? book,
|
||||||
final String heroTagSuffix,
|
final String heroTagSuffix}) = _$LibraryItemExtrasImpl;
|
||||||
final Uint8List? coverImage}) = _$LibraryItemExtrasImpl;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
BookMinified? get book;
|
BookMinified? get book;
|
||||||
@override
|
@override
|
||||||
String get heroTagSuffix;
|
String get heroTagSuffix;
|
||||||
@override
|
|
||||||
Uint8List? get coverImage;
|
|
||||||
|
|
||||||
/// Create a copy of LibraryItemExtras
|
/// Create a copy of LibraryItemExtras
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
|
|
||||||
|
|
@ -8,8 +8,7 @@ import 'package:shelfsdk/audiobookshelf_api.dart';
|
||||||
import 'package:shimmer/shimmer.dart' show Shimmer;
|
import 'package:shimmer/shimmer.dart' show Shimmer;
|
||||||
import 'package:vaani/api/api_provider.dart';
|
import 'package:vaani/api/api_provider.dart';
|
||||||
import 'package:vaani/api/image_provider.dart';
|
import 'package:vaani/api/image_provider.dart';
|
||||||
import 'package:vaani/api/library_item_provider.dart'
|
import 'package:vaani/api/library_item_provider.dart' show libraryItemProvider;
|
||||||
show libraryItemProvider;
|
|
||||||
import 'package:vaani/constants/hero_tag_conventions.dart';
|
import 'package:vaani/constants/hero_tag_conventions.dart';
|
||||||
import 'package:vaani/features/item_viewer/view/library_item_actions.dart';
|
import 'package:vaani/features/item_viewer/view/library_item_actions.dart';
|
||||||
import 'package:vaani/features/player/providers/audiobook_player.dart';
|
import 'package:vaani/features/player/providers/audiobook_player.dart';
|
||||||
|
|
@ -72,7 +71,7 @@ class BookOnShelf extends HookConsumerWidget {
|
||||||
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 coverImage = ref.watch(coverImageProvider(item));
|
final coverImage = ref.watch(coverImageProvider(item.id));
|
||||||
return LayoutBuilder(
|
return LayoutBuilder(
|
||||||
builder: (context, constraints) {
|
builder: (context, constraints) {
|
||||||
final height = min(constraints.maxHeight, 500);
|
final height = min(constraints.maxHeight, 500);
|
||||||
|
|
@ -87,7 +86,6 @@ class BookOnShelf extends HookConsumerWidget {
|
||||||
extra: LibraryItemExtras(
|
extra: LibraryItemExtras(
|
||||||
book: book,
|
book: book,
|
||||||
heroTagSuffix: heroTagSuffix,
|
heroTagSuffix: heroTagSuffix,
|
||||||
coverImage: coverImage.valueOrNull,
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -228,10 +226,9 @@ class _BookOnShelfPlayButton extends HookConsumerWidget {
|
||||||
|
|
||||||
AsyncValue<ColorScheme?> coverColorScheme = const AsyncValue.loading();
|
AsyncValue<ColorScheme?> coverColorScheme = const AsyncValue.loading();
|
||||||
if (useMaterialThemeOnItemPage && isCurrentBookSetInPlayer) {
|
if (useMaterialThemeOnItemPage && isCurrentBookSetInPlayer) {
|
||||||
final itemFromApi = ref.watch(libraryItemProvider(libraryItemId));
|
|
||||||
coverColorScheme = ref.watch(
|
coverColorScheme = ref.watch(
|
||||||
themeOfLibraryItemProvider(
|
themeOfLibraryItemProvider(
|
||||||
itemFromApi.valueOrNull,
|
libraryItemId,
|
||||||
brightness: Theme.of(context).brightness,
|
brightness: Theme.of(context).brightness,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_animate/flutter_animate.dart';
|
import 'package:flutter_animate/flutter_animate.dart';
|
||||||
import 'package:logging/logging.dart';
|
import 'package:logging/logging.dart';
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
import 'package:shelfsdk/audiobookshelf_api.dart';
|
|
||||||
import 'package:vaani/api/image_provider.dart';
|
import 'package:vaani/api/image_provider.dart';
|
||||||
|
|
||||||
part 'theme_from_cover_provider.g.dart';
|
part 'theme_from_cover_provider.g.dart';
|
||||||
|
|
@ -49,13 +48,13 @@ Future<FutureOr<ColorScheme?>> themeFromCover(
|
||||||
@Riverpod(keepAlive: true)
|
@Riverpod(keepAlive: true)
|
||||||
FutureOr<ColorScheme?> themeOfLibraryItem(
|
FutureOr<ColorScheme?> themeOfLibraryItem(
|
||||||
ThemeOfLibraryItemRef ref,
|
ThemeOfLibraryItemRef ref,
|
||||||
LibraryItem? item, {
|
String? itemId, {
|
||||||
Brightness brightness = Brightness.dark,
|
Brightness brightness = Brightness.dark,
|
||||||
}) async {
|
}) async {
|
||||||
if (item == null) {
|
if (itemId == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
final coverImage = await ref.watch(coverImageProvider(item).future);
|
final coverImage = await ref.watch(coverImageProvider(itemId).future);
|
||||||
final val = await ref.watch(
|
final val = await ref.watch(
|
||||||
themeFromCoverProvider(MemoryImage(coverImage), brightness: brightness)
|
themeFromCoverProvider(MemoryImage(coverImage), brightness: brightness)
|
||||||
.future,
|
.future,
|
||||||
|
|
|
||||||
|
|
@ -175,7 +175,7 @@ class _ThemeFromCoverProviderElement
|
||||||
}
|
}
|
||||||
|
|
||||||
String _$themeOfLibraryItemHash() =>
|
String _$themeOfLibraryItemHash() =>
|
||||||
r'575a390a0ab0e66cf54cb090a358c08847270798';
|
r'a1d0e5d81f4debe88d5a6ce46c3af28623ad4273';
|
||||||
|
|
||||||
/// See also [themeOfLibraryItem].
|
/// See also [themeOfLibraryItem].
|
||||||
@ProviderFor(themeOfLibraryItem)
|
@ProviderFor(themeOfLibraryItem)
|
||||||
|
|
@ -188,11 +188,11 @@ class ThemeOfLibraryItemFamily extends Family<AsyncValue<ColorScheme?>> {
|
||||||
|
|
||||||
/// See also [themeOfLibraryItem].
|
/// See also [themeOfLibraryItem].
|
||||||
ThemeOfLibraryItemProvider call(
|
ThemeOfLibraryItemProvider call(
|
||||||
LibraryItem? item, {
|
String? itemId, {
|
||||||
Brightness brightness = Brightness.dark,
|
Brightness brightness = Brightness.dark,
|
||||||
}) {
|
}) {
|
||||||
return ThemeOfLibraryItemProvider(
|
return ThemeOfLibraryItemProvider(
|
||||||
item,
|
itemId,
|
||||||
brightness: brightness,
|
brightness: brightness,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -202,7 +202,7 @@ class ThemeOfLibraryItemFamily extends Family<AsyncValue<ColorScheme?>> {
|
||||||
covariant ThemeOfLibraryItemProvider provider,
|
covariant ThemeOfLibraryItemProvider provider,
|
||||||
) {
|
) {
|
||||||
return call(
|
return call(
|
||||||
provider.item,
|
provider.itemId,
|
||||||
brightness: provider.brightness,
|
brightness: provider.brightness,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -226,12 +226,12 @@ class ThemeOfLibraryItemFamily extends Family<AsyncValue<ColorScheme?>> {
|
||||||
class ThemeOfLibraryItemProvider extends FutureProvider<ColorScheme?> {
|
class ThemeOfLibraryItemProvider extends FutureProvider<ColorScheme?> {
|
||||||
/// See also [themeOfLibraryItem].
|
/// See also [themeOfLibraryItem].
|
||||||
ThemeOfLibraryItemProvider(
|
ThemeOfLibraryItemProvider(
|
||||||
LibraryItem? item, {
|
String? itemId, {
|
||||||
Brightness brightness = Brightness.dark,
|
Brightness brightness = Brightness.dark,
|
||||||
}) : this._internal(
|
}) : this._internal(
|
||||||
(ref) => themeOfLibraryItem(
|
(ref) => themeOfLibraryItem(
|
||||||
ref as ThemeOfLibraryItemRef,
|
ref as ThemeOfLibraryItemRef,
|
||||||
item,
|
itemId,
|
||||||
brightness: brightness,
|
brightness: brightness,
|
||||||
),
|
),
|
||||||
from: themeOfLibraryItemProvider,
|
from: themeOfLibraryItemProvider,
|
||||||
|
|
@ -243,7 +243,7 @@ class ThemeOfLibraryItemProvider extends FutureProvider<ColorScheme?> {
|
||||||
dependencies: ThemeOfLibraryItemFamily._dependencies,
|
dependencies: ThemeOfLibraryItemFamily._dependencies,
|
||||||
allTransitiveDependencies:
|
allTransitiveDependencies:
|
||||||
ThemeOfLibraryItemFamily._allTransitiveDependencies,
|
ThemeOfLibraryItemFamily._allTransitiveDependencies,
|
||||||
item: item,
|
itemId: itemId,
|
||||||
brightness: brightness,
|
brightness: brightness,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -254,11 +254,11 @@ class ThemeOfLibraryItemProvider extends FutureProvider<ColorScheme?> {
|
||||||
required super.allTransitiveDependencies,
|
required super.allTransitiveDependencies,
|
||||||
required super.debugGetCreateSourceHash,
|
required super.debugGetCreateSourceHash,
|
||||||
required super.from,
|
required super.from,
|
||||||
required this.item,
|
required this.itemId,
|
||||||
required this.brightness,
|
required this.brightness,
|
||||||
}) : super.internal();
|
}) : super.internal();
|
||||||
|
|
||||||
final LibraryItem? item;
|
final String? itemId;
|
||||||
final Brightness brightness;
|
final Brightness brightness;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
@ -274,7 +274,7 @@ class ThemeOfLibraryItemProvider extends FutureProvider<ColorScheme?> {
|
||||||
dependencies: null,
|
dependencies: null,
|
||||||
allTransitiveDependencies: null,
|
allTransitiveDependencies: null,
|
||||||
debugGetCreateSourceHash: null,
|
debugGetCreateSourceHash: null,
|
||||||
item: item,
|
itemId: itemId,
|
||||||
brightness: brightness,
|
brightness: brightness,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
@ -288,14 +288,14 @@ class ThemeOfLibraryItemProvider extends FutureProvider<ColorScheme?> {
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) {
|
bool operator ==(Object other) {
|
||||||
return other is ThemeOfLibraryItemProvider &&
|
return other is ThemeOfLibraryItemProvider &&
|
||||||
other.item == item &&
|
other.itemId == itemId &&
|
||||||
other.brightness == brightness;
|
other.brightness == brightness;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int get hashCode {
|
int get hashCode {
|
||||||
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
||||||
hash = _SystemHash.combine(hash, item.hashCode);
|
hash = _SystemHash.combine(hash, itemId.hashCode);
|
||||||
hash = _SystemHash.combine(hash, brightness.hashCode);
|
hash = _SystemHash.combine(hash, brightness.hashCode);
|
||||||
|
|
||||||
return _SystemHash.finish(hash);
|
return _SystemHash.finish(hash);
|
||||||
|
|
@ -303,8 +303,8 @@ class ThemeOfLibraryItemProvider extends FutureProvider<ColorScheme?> {
|
||||||
}
|
}
|
||||||
|
|
||||||
mixin ThemeOfLibraryItemRef on FutureProviderRef<ColorScheme?> {
|
mixin ThemeOfLibraryItemRef on FutureProviderRef<ColorScheme?> {
|
||||||
/// The parameter `item` of this provider.
|
/// The parameter `itemId` of this provider.
|
||||||
LibraryItem? get item;
|
String? get itemId;
|
||||||
|
|
||||||
/// The parameter `brightness` of this provider.
|
/// The parameter `brightness` of this provider.
|
||||||
Brightness get brightness;
|
Brightness get brightness;
|
||||||
|
|
@ -315,7 +315,7 @@ class _ThemeOfLibraryItemProviderElement
|
||||||
_ThemeOfLibraryItemProviderElement(super.provider);
|
_ThemeOfLibraryItemProviderElement(super.provider);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
LibraryItem? get item => (origin as ThemeOfLibraryItemProvider).item;
|
String? get itemId => (origin as ThemeOfLibraryItemProvider).itemId;
|
||||||
@override
|
@override
|
||||||
Brightness get brightness =>
|
Brightness get brightness =>
|
||||||
(origin as ThemeOfLibraryItemProvider).brightness;
|
(origin as ThemeOfLibraryItemProvider).brightness;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue