mirror of
https://github.com/Dr-Blank/Vaani.git
synced 2026-07-06 17:31:33 +00:00
feat: add total size calculation for library items and improve download manager functionality
This commit is contained in:
parent
30f87c422b
commit
b0cc1ff8cb
5 changed files with 190 additions and 196 deletions
|
|
@ -92,50 +92,13 @@ class AudiobookDownloadManager {
|
|||
allowPause: allowPause,
|
||||
group: item.id,
|
||||
baseDirectory: downloadDirectory,
|
||||
updates: Updates.statusAndProgress,
|
||||
// metaData: token
|
||||
);
|
||||
// _downloadTasks.add(task);
|
||||
tq.add(task);
|
||||
_logger.info('queued task: ${task.taskId}');
|
||||
}
|
||||
|
||||
FileDownloader().registerCallbacks(
|
||||
group: item.id,
|
||||
taskProgressCallback: (update) {
|
||||
try {
|
||||
taskProgressCallback?.call(update);
|
||||
} catch (e) {
|
||||
_logger.warning('Error in taskProgressCallback: $e');
|
||||
}
|
||||
_logger.info('Group: ${item.id}, Progress Update: ${update.progress}');
|
||||
},
|
||||
taskStatusCallback: (update) {
|
||||
try {
|
||||
taskStatusCallback?.call(update);
|
||||
} catch (e) {
|
||||
_logger.warning('Error in taskStatusCallback: $e');
|
||||
}
|
||||
switch (update.status) {
|
||||
case TaskStatus.complete:
|
||||
_logger.info('Group: ${item.id}, Download Complete');
|
||||
break;
|
||||
case TaskStatus.failed:
|
||||
_logger.warning('Group: ${item.id}, Download Failed');
|
||||
break;
|
||||
default:
|
||||
_logger
|
||||
.info('Group: ${item.id}, Download Status: ${update.status}');
|
||||
}
|
||||
},
|
||||
taskNotificationTapCallback: (task, notificationType) {
|
||||
try {
|
||||
taskNotificationTapCallback?.call(task, notificationType);
|
||||
} catch (e) {
|
||||
_logger.warning('Error in taskNotificationTapCallback: $e');
|
||||
}
|
||||
_logger.info('Group: ${item.id}, Task: ${task.taskId}');
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
String constructFilePath(
|
||||
|
|
@ -152,10 +115,6 @@ class AudiobookDownloadManager {
|
|||
}
|
||||
|
||||
bool isItemDownloading(String id) {
|
||||
if (tq.isEmpty) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return tq.enqueued.any((task) => task.group == id);
|
||||
}
|
||||
|
||||
|
|
@ -164,6 +123,29 @@ class AudiobookDownloadManager {
|
|||
return fileExists;
|
||||
}
|
||||
|
||||
Future<List<LibraryFile>> getDownloadedFilesMetadata(
|
||||
LibraryItemExpanded item,
|
||||
) async {
|
||||
final directory = await getApplicationSupportDirectory();
|
||||
final downloadedFiles = <LibraryFile>[];
|
||||
for (final file in item.libraryFiles) {
|
||||
final filePath = constructFilePath(directory, item, file);
|
||||
if (isFileDownloaded(filePath)) {
|
||||
downloadedFiles.add(file);
|
||||
}
|
||||
}
|
||||
|
||||
return downloadedFiles;
|
||||
}
|
||||
|
||||
Future<int> getDownloadedSize(LibraryItemExpanded item) async {
|
||||
final files = await getDownloadedFilesMetadata(item);
|
||||
return files.fold<int>(
|
||||
0,
|
||||
(previousValue, element) => previousValue + element.metadata.size,
|
||||
);
|
||||
}
|
||||
|
||||
Future<bool> isItemDownloaded(LibraryItemExpanded item) async {
|
||||
final directory = await getApplicationSupportDirectory();
|
||||
for (final file in item.libraryFiles) {
|
||||
|
|
@ -188,7 +170,7 @@ class AudiobookDownloadManager {
|
|||
}
|
||||
}
|
||||
|
||||
Future<List<Uri>> getDownloadedFiles(LibraryItemExpanded item) async {
|
||||
Future<List<Uri>> getDownloadedFilesUri(LibraryItemExpanded item) async {
|
||||
final directory = await getApplicationSupportDirectory();
|
||||
final files = <Uri>[];
|
||||
for (final file in item.libraryFiles) {
|
||||
|
|
@ -214,12 +196,12 @@ class AudiobookDownloadManager {
|
|||
|
||||
await fileDownloader.trackTasks();
|
||||
|
||||
_logger.info('Listening to download manager updates');
|
||||
try {
|
||||
_updatesSubscription = fileDownloader.updates.listen((event) {
|
||||
_logger.info('Got event: $event');
|
||||
_updatesSubscription = fileDownloader.updates.listen((event) {
|
||||
_logger.finer('Got event: $event');
|
||||
_taskStatusController.add(event);
|
||||
});
|
||||
_logger.info('Listening to download manager updates');
|
||||
} catch (e) {
|
||||
_logger.warning('Error when listening to download manager updates: $e');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,8 +3,10 @@ import 'package:logging/logging.dart';
|
|||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
import 'package:shelfsdk/audiobookshelf_api.dart';
|
||||
import 'package:vaani/api/api_provider.dart';
|
||||
import 'package:vaani/api/library_item_provider.dart';
|
||||
import 'package:vaani/features/downloads/core/download_manager.dart' as core;
|
||||
import 'package:vaani/settings/app_settings_provider.dart';
|
||||
import 'package:vaani/shared/extensions/item_files.dart';
|
||||
|
||||
part 'download_manager.g.dart';
|
||||
|
||||
|
|
@ -36,15 +38,11 @@ class SimpleDownloadManager extends _$SimpleDownloadManager {
|
|||
}
|
||||
}
|
||||
|
||||
@riverpod
|
||||
@Riverpod(keepAlive: true)
|
||||
class DownloadManager extends _$DownloadManager {
|
||||
@override
|
||||
core.AudiobookDownloadManager build() {
|
||||
final manager = ref.watch(simpleDownloadManagerProvider);
|
||||
ref.onDispose(() {
|
||||
manager.dispose();
|
||||
});
|
||||
|
||||
manager.taskUpdateStream.listen((_) {
|
||||
ref.notifyListeners();
|
||||
});
|
||||
|
|
@ -87,49 +85,52 @@ class DownloadManager extends _$DownloadManager {
|
|||
class IsItemDownloading extends _$IsItemDownloading {
|
||||
@override
|
||||
bool build(String id) {
|
||||
final manager = ref.read(downloadManagerProvider);
|
||||
ref.onDispose(() {
|
||||
manager.dispose();
|
||||
});
|
||||
|
||||
callback(dynamic _) {
|
||||
ref.notifyListeners();
|
||||
}
|
||||
|
||||
FileDownloader().registerCallbacks(
|
||||
group: id,
|
||||
taskStatusCallback: callback,
|
||||
);
|
||||
|
||||
ref.onDispose(() {
|
||||
FileDownloader().unregisterCallbacks(group: id, callback: callback);
|
||||
});
|
||||
|
||||
final manager = ref.watch(downloadManagerProvider);
|
||||
return manager.isItemDownloading(id);
|
||||
}
|
||||
}
|
||||
|
||||
@Riverpod(keepAlive: true)
|
||||
class DownloadProgress extends _$DownloadProgress {
|
||||
@riverpod
|
||||
class ItemDownloadProgress extends _$ItemDownloadProgress {
|
||||
@override
|
||||
double build(String id) {
|
||||
var progress = 0.0;
|
||||
Future<double?> build(String id) async {
|
||||
final item = await ref.watch(libraryItemProvider(id).future);
|
||||
final manager = ref.read(downloadManagerProvider);
|
||||
manager.taskUpdateStream.map((taskUpdate) {
|
||||
if (taskUpdate is! TaskProgressUpdate) {
|
||||
return null;
|
||||
}
|
||||
if (taskUpdate.task.group == id) {
|
||||
return taskUpdate;
|
||||
}
|
||||
}).listen((task) async {
|
||||
if (task != null) {
|
||||
final totalSize = item.totalSize;
|
||||
// if total size is 0, return 0
|
||||
if (totalSize == 0) {
|
||||
state = const AsyncValue.data(0.0);
|
||||
return;
|
||||
}
|
||||
final downloadedFiles = await manager.getDownloadedFilesMetadata(item);
|
||||
// calculate total size of downloaded files and total size of item, then divide
|
||||
// to get percentage
|
||||
final downloadedSize = downloadedFiles.fold<int>(
|
||||
0,
|
||||
(previousValue, element) => previousValue + element.metadata.size,
|
||||
);
|
||||
|
||||
void progressCallback(TaskProgressUpdate progress) {
|
||||
state = progress.progress;
|
||||
}
|
||||
final inProgressFileSize = task.progress * task.expectedFileSize;
|
||||
final totalDownloadedSize = downloadedSize + inProgressFileSize;
|
||||
final progress = totalDownloadedSize / totalSize;
|
||||
// if current progress is more than calculated progress, do not update
|
||||
if (progress < (state.valueOrNull ?? 0.0)) {
|
||||
return;
|
||||
}
|
||||
|
||||
FileDownloader().registerCallbacks(
|
||||
group: id,
|
||||
taskProgressCallback: progressCallback,
|
||||
);
|
||||
|
||||
ref.onDispose(() {
|
||||
FileDownloader()
|
||||
.unregisterCallbacks(group: id, callback: progressCallback);
|
||||
state = AsyncValue.data(progress.clamp(0.0, 1.0));
|
||||
}
|
||||
});
|
||||
|
||||
return progress;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -141,17 +142,8 @@ FutureOr<List<TaskRecord>> downloadHistory(
|
|||
return await FileDownloader().database.allRecords(group: group);
|
||||
}
|
||||
|
||||
// @Riverpod(keepAlive: false)
|
||||
// FutureOr<bool> downloadStatus(
|
||||
// DownloadStatusRef ref,
|
||||
// LibraryItemExpanded item,
|
||||
// ) async {
|
||||
// final manager = ref.read(simpleDownloadManagerProvider);
|
||||
// return manager.isItemDownloaded(item);
|
||||
// }
|
||||
|
||||
@riverpod
|
||||
class DownloadStatus extends _$DownloadStatus {
|
||||
class IsItemDownloaded extends _$IsItemDownloaded {
|
||||
@override
|
||||
FutureOr<bool> build(
|
||||
LibraryItemExpanded item,
|
||||
|
|
@ -159,5 +151,4 @@ class DownloadStatus extends _$DownloadStatus {
|
|||
final manager = ref.watch(downloadManagerProvider);
|
||||
return manager.isItemDownloaded(item);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -174,12 +174,12 @@ final simpleDownloadManagerProvider = NotifierProvider<SimpleDownloadManager,
|
|||
);
|
||||
|
||||
typedef _$SimpleDownloadManager = Notifier<core.AudiobookDownloadManager>;
|
||||
String _$downloadManagerHash() => r'bf08bdeda54773a4b6713ad77abb75add3ed30ee';
|
||||
String _$downloadManagerHash() => r'9566b772d792b32e1b199d4aa834e28de3b034d0';
|
||||
|
||||
/// See also [DownloadManager].
|
||||
@ProviderFor(DownloadManager)
|
||||
final downloadManagerProvider = AutoDisposeNotifierProvider<DownloadManager,
|
||||
core.AudiobookDownloadManager>.internal(
|
||||
final downloadManagerProvider =
|
||||
NotifierProvider<DownloadManager, core.AudiobookDownloadManager>.internal(
|
||||
DownloadManager.new,
|
||||
name: r'downloadManagerProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
|
|
@ -189,8 +189,8 @@ final downloadManagerProvider = AutoDisposeNotifierProvider<DownloadManager,
|
|||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
typedef _$DownloadManager = AutoDisposeNotifier<core.AudiobookDownloadManager>;
|
||||
String _$isItemDownloadingHash() => r'07e35ae25c096e9c9071667c6303a43f7b5e4cff';
|
||||
typedef _$DownloadManager = Notifier<core.AudiobookDownloadManager>;
|
||||
String _$isItemDownloadingHash() => r'ea43c06393beec828134e08d5f896ddbcfbac8f0';
|
||||
|
||||
abstract class _$IsItemDownloading extends BuildlessAutoDisposeNotifier<bool> {
|
||||
late final String id;
|
||||
|
|
@ -332,37 +332,39 @@ class _IsItemDownloadingProviderElement
|
|||
String get id => (origin as IsItemDownloadingProvider).id;
|
||||
}
|
||||
|
||||
String _$downloadProgressHash() => r'1677f45191181765f6efebdb74206a438a47a4b7';
|
||||
String _$itemDownloadProgressHash() =>
|
||||
r'd007c55c6e2e4b992069d0306df8a600225d8598';
|
||||
|
||||
abstract class _$DownloadProgress extends BuildlessNotifier<double> {
|
||||
abstract class _$ItemDownloadProgress
|
||||
extends BuildlessAutoDisposeAsyncNotifier<double?> {
|
||||
late final String id;
|
||||
|
||||
double build(
|
||||
FutureOr<double?> build(
|
||||
String id,
|
||||
);
|
||||
}
|
||||
|
||||
/// See also [DownloadProgress].
|
||||
@ProviderFor(DownloadProgress)
|
||||
const downloadProgressProvider = DownloadProgressFamily();
|
||||
/// See also [ItemDownloadProgress].
|
||||
@ProviderFor(ItemDownloadProgress)
|
||||
const itemDownloadProgressProvider = ItemDownloadProgressFamily();
|
||||
|
||||
/// See also [DownloadProgress].
|
||||
class DownloadProgressFamily extends Family<double> {
|
||||
/// See also [DownloadProgress].
|
||||
const DownloadProgressFamily();
|
||||
/// See also [ItemDownloadProgress].
|
||||
class ItemDownloadProgressFamily extends Family<AsyncValue<double?>> {
|
||||
/// See also [ItemDownloadProgress].
|
||||
const ItemDownloadProgressFamily();
|
||||
|
||||
/// See also [DownloadProgress].
|
||||
DownloadProgressProvider call(
|
||||
/// See also [ItemDownloadProgress].
|
||||
ItemDownloadProgressProvider call(
|
||||
String id,
|
||||
) {
|
||||
return DownloadProgressProvider(
|
||||
return ItemDownloadProgressProvider(
|
||||
id,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
DownloadProgressProvider getProviderOverride(
|
||||
covariant DownloadProgressProvider provider,
|
||||
ItemDownloadProgressProvider getProviderOverride(
|
||||
covariant ItemDownloadProgressProvider provider,
|
||||
) {
|
||||
return call(
|
||||
provider.id,
|
||||
|
|
@ -381,30 +383,30 @@ class DownloadProgressFamily extends Family<double> {
|
|||
_allTransitiveDependencies;
|
||||
|
||||
@override
|
||||
String? get name => r'downloadProgressProvider';
|
||||
String? get name => r'itemDownloadProgressProvider';
|
||||
}
|
||||
|
||||
/// See also [DownloadProgress].
|
||||
class DownloadProgressProvider
|
||||
extends NotifierProviderImpl<DownloadProgress, double> {
|
||||
/// See also [DownloadProgress].
|
||||
DownloadProgressProvider(
|
||||
/// See also [ItemDownloadProgress].
|
||||
class ItemDownloadProgressProvider extends AutoDisposeAsyncNotifierProviderImpl<
|
||||
ItemDownloadProgress, double?> {
|
||||
/// See also [ItemDownloadProgress].
|
||||
ItemDownloadProgressProvider(
|
||||
String id,
|
||||
) : this._internal(
|
||||
() => DownloadProgress()..id = id,
|
||||
from: downloadProgressProvider,
|
||||
name: r'downloadProgressProvider',
|
||||
() => ItemDownloadProgress()..id = id,
|
||||
from: itemDownloadProgressProvider,
|
||||
name: r'itemDownloadProgressProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$downloadProgressHash,
|
||||
dependencies: DownloadProgressFamily._dependencies,
|
||||
: _$itemDownloadProgressHash,
|
||||
dependencies: ItemDownloadProgressFamily._dependencies,
|
||||
allTransitiveDependencies:
|
||||
DownloadProgressFamily._allTransitiveDependencies,
|
||||
ItemDownloadProgressFamily._allTransitiveDependencies,
|
||||
id: id,
|
||||
);
|
||||
|
||||
DownloadProgressProvider._internal(
|
||||
ItemDownloadProgressProvider._internal(
|
||||
super._createNotifier, {
|
||||
required super.name,
|
||||
required super.dependencies,
|
||||
|
|
@ -417,8 +419,8 @@ class DownloadProgressProvider
|
|||
final String id;
|
||||
|
||||
@override
|
||||
double runNotifierBuild(
|
||||
covariant DownloadProgress notifier,
|
||||
FutureOr<double?> runNotifierBuild(
|
||||
covariant ItemDownloadProgress notifier,
|
||||
) {
|
||||
return notifier.build(
|
||||
id,
|
||||
|
|
@ -426,10 +428,10 @@ class DownloadProgressProvider
|
|||
}
|
||||
|
||||
@override
|
||||
Override overrideWith(DownloadProgress Function() create) {
|
||||
Override overrideWith(ItemDownloadProgress Function() create) {
|
||||
return ProviderOverride(
|
||||
origin: this,
|
||||
override: DownloadProgressProvider._internal(
|
||||
override: ItemDownloadProgressProvider._internal(
|
||||
() => create()..id = id,
|
||||
from: from,
|
||||
name: null,
|
||||
|
|
@ -442,13 +444,14 @@ class DownloadProgressProvider
|
|||
}
|
||||
|
||||
@override
|
||||
NotifierProviderElement<DownloadProgress, double> createElement() {
|
||||
return _DownloadProgressProviderElement(this);
|
||||
AutoDisposeAsyncNotifierProviderElement<ItemDownloadProgress, double?>
|
||||
createElement() {
|
||||
return _ItemDownloadProgressProviderElement(this);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is DownloadProgressProvider && other.id == id;
|
||||
return other is ItemDownloadProgressProvider && other.id == id;
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
@ -460,23 +463,23 @@ class DownloadProgressProvider
|
|||
}
|
||||
}
|
||||
|
||||
mixin DownloadProgressRef on NotifierProviderRef<double> {
|
||||
mixin ItemDownloadProgressRef on AutoDisposeAsyncNotifierProviderRef<double?> {
|
||||
/// The parameter `id` of this provider.
|
||||
String get id;
|
||||
}
|
||||
|
||||
class _DownloadProgressProviderElement
|
||||
extends NotifierProviderElement<DownloadProgress, double>
|
||||
with DownloadProgressRef {
|
||||
_DownloadProgressProviderElement(super.provider);
|
||||
class _ItemDownloadProgressProviderElement
|
||||
extends AutoDisposeAsyncNotifierProviderElement<ItemDownloadProgress,
|
||||
double?> with ItemDownloadProgressRef {
|
||||
_ItemDownloadProgressProviderElement(super.provider);
|
||||
|
||||
@override
|
||||
String get id => (origin as DownloadProgressProvider).id;
|
||||
String get id => (origin as ItemDownloadProgressProvider).id;
|
||||
}
|
||||
|
||||
String _$downloadStatusHash() => r'3f2bf4e7fb01b9329d31f4797537a307aff70397';
|
||||
String _$isItemDownloadedHash() => r'9bb7ba28bdb73e1ba706e849fedc9c7bd67f4b67';
|
||||
|
||||
abstract class _$DownloadStatus
|
||||
abstract class _$IsItemDownloaded
|
||||
extends BuildlessAutoDisposeAsyncNotifier<bool> {
|
||||
late final LibraryItemExpanded item;
|
||||
|
||||
|
|
@ -485,27 +488,27 @@ abstract class _$DownloadStatus
|
|||
);
|
||||
}
|
||||
|
||||
/// See also [DownloadStatus].
|
||||
@ProviderFor(DownloadStatus)
|
||||
const downloadStatusProvider = DownloadStatusFamily();
|
||||
/// See also [IsItemDownloaded].
|
||||
@ProviderFor(IsItemDownloaded)
|
||||
const isItemDownloadedProvider = IsItemDownloadedFamily();
|
||||
|
||||
/// See also [DownloadStatus].
|
||||
class DownloadStatusFamily extends Family<AsyncValue<bool>> {
|
||||
/// See also [DownloadStatus].
|
||||
const DownloadStatusFamily();
|
||||
/// See also [IsItemDownloaded].
|
||||
class IsItemDownloadedFamily extends Family<AsyncValue<bool>> {
|
||||
/// See also [IsItemDownloaded].
|
||||
const IsItemDownloadedFamily();
|
||||
|
||||
/// See also [DownloadStatus].
|
||||
DownloadStatusProvider call(
|
||||
/// See also [IsItemDownloaded].
|
||||
IsItemDownloadedProvider call(
|
||||
LibraryItemExpanded item,
|
||||
) {
|
||||
return DownloadStatusProvider(
|
||||
return IsItemDownloadedProvider(
|
||||
item,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
DownloadStatusProvider getProviderOverride(
|
||||
covariant DownloadStatusProvider provider,
|
||||
IsItemDownloadedProvider getProviderOverride(
|
||||
covariant IsItemDownloadedProvider provider,
|
||||
) {
|
||||
return call(
|
||||
provider.item,
|
||||
|
|
@ -524,30 +527,30 @@ class DownloadStatusFamily extends Family<AsyncValue<bool>> {
|
|||
_allTransitiveDependencies;
|
||||
|
||||
@override
|
||||
String? get name => r'downloadStatusProvider';
|
||||
String? get name => r'isItemDownloadedProvider';
|
||||
}
|
||||
|
||||
/// See also [DownloadStatus].
|
||||
class DownloadStatusProvider
|
||||
extends AutoDisposeAsyncNotifierProviderImpl<DownloadStatus, bool> {
|
||||
/// See also [DownloadStatus].
|
||||
DownloadStatusProvider(
|
||||
/// See also [IsItemDownloaded].
|
||||
class IsItemDownloadedProvider
|
||||
extends AutoDisposeAsyncNotifierProviderImpl<IsItemDownloaded, bool> {
|
||||
/// See also [IsItemDownloaded].
|
||||
IsItemDownloadedProvider(
|
||||
LibraryItemExpanded item,
|
||||
) : this._internal(
|
||||
() => DownloadStatus()..item = item,
|
||||
from: downloadStatusProvider,
|
||||
name: r'downloadStatusProvider',
|
||||
() => IsItemDownloaded()..item = item,
|
||||
from: isItemDownloadedProvider,
|
||||
name: r'isItemDownloadedProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$downloadStatusHash,
|
||||
dependencies: DownloadStatusFamily._dependencies,
|
||||
: _$isItemDownloadedHash,
|
||||
dependencies: IsItemDownloadedFamily._dependencies,
|
||||
allTransitiveDependencies:
|
||||
DownloadStatusFamily._allTransitiveDependencies,
|
||||
IsItemDownloadedFamily._allTransitiveDependencies,
|
||||
item: item,
|
||||
);
|
||||
|
||||
DownloadStatusProvider._internal(
|
||||
IsItemDownloadedProvider._internal(
|
||||
super._createNotifier, {
|
||||
required super.name,
|
||||
required super.dependencies,
|
||||
|
|
@ -561,7 +564,7 @@ class DownloadStatusProvider
|
|||
|
||||
@override
|
||||
FutureOr<bool> runNotifierBuild(
|
||||
covariant DownloadStatus notifier,
|
||||
covariant IsItemDownloaded notifier,
|
||||
) {
|
||||
return notifier.build(
|
||||
item,
|
||||
|
|
@ -569,10 +572,10 @@ class DownloadStatusProvider
|
|||
}
|
||||
|
||||
@override
|
||||
Override overrideWith(DownloadStatus Function() create) {
|
||||
Override overrideWith(IsItemDownloaded Function() create) {
|
||||
return ProviderOverride(
|
||||
origin: this,
|
||||
override: DownloadStatusProvider._internal(
|
||||
override: IsItemDownloadedProvider._internal(
|
||||
() => create()..item = item,
|
||||
from: from,
|
||||
name: null,
|
||||
|
|
@ -585,14 +588,14 @@ class DownloadStatusProvider
|
|||
}
|
||||
|
||||
@override
|
||||
AutoDisposeAsyncNotifierProviderElement<DownloadStatus, bool>
|
||||
AutoDisposeAsyncNotifierProviderElement<IsItemDownloaded, bool>
|
||||
createElement() {
|
||||
return _DownloadStatusProviderElement(this);
|
||||
return _IsItemDownloadedProviderElement(this);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is DownloadStatusProvider && other.item == item;
|
||||
return other is IsItemDownloadedProvider && other.item == item;
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
@ -604,18 +607,18 @@ class DownloadStatusProvider
|
|||
}
|
||||
}
|
||||
|
||||
mixin DownloadStatusRef on AutoDisposeAsyncNotifierProviderRef<bool> {
|
||||
mixin IsItemDownloadedRef on AutoDisposeAsyncNotifierProviderRef<bool> {
|
||||
/// The parameter `item` of this provider.
|
||||
LibraryItemExpanded get item;
|
||||
}
|
||||
|
||||
class _DownloadStatusProviderElement
|
||||
extends AutoDisposeAsyncNotifierProviderElement<DownloadStatus, bool>
|
||||
with DownloadStatusRef {
|
||||
_DownloadStatusProviderElement(super.provider);
|
||||
class _IsItemDownloadedProviderElement
|
||||
extends AutoDisposeAsyncNotifierProviderElement<IsItemDownloaded, bool>
|
||||
with IsItemDownloadedRef {
|
||||
_IsItemDownloadedProviderElement(super.provider);
|
||||
|
||||
@override
|
||||
LibraryItemExpanded get item => (origin as DownloadStatusProvider).item;
|
||||
LibraryItemExpanded get item => (origin as IsItemDownloadedProvider).item;
|
||||
}
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import 'package:background_downloader/background_downloader.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_animate/flutter_animate.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:shelfsdk/audiobookshelf_api.dart' as shelfsdk;
|
||||
|
|
@ -11,9 +10,9 @@ import 'package:vaani/features/downloads/providers/download_manager.dart'
|
|||
show
|
||||
downloadHistoryProvider,
|
||||
downloadManagerProvider,
|
||||
downloadProgressProvider,
|
||||
downloadStatusProvider,
|
||||
isItemDownloadedProvider,
|
||||
isItemDownloadingProvider,
|
||||
itemDownloadProgressProvider,
|
||||
simpleDownloadManagerProvider;
|
||||
import 'package:vaani/features/item_viewer/view/library_item_page.dart';
|
||||
import 'package:vaani/features/per_book_settings/providers/book_settings_provider.dart';
|
||||
|
|
@ -214,12 +213,13 @@ class LibItemDownloadButton extends HookConsumerWidget {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final isItemDownloaded = ref.watch(downloadStatusProvider(item));
|
||||
final isItemDownloaded = ref.watch(isItemDownloadedProvider(item));
|
||||
if (isItemDownloaded.valueOrNull ?? false) {
|
||||
return AlreadyItemDownloadedButton(item: item);
|
||||
}
|
||||
final isItemDownloading = ref.watch(isItemDownloadingProvider(item.id));
|
||||
|
||||
return isItemDownloaded.valueOrNull ?? false
|
||||
? AlreadyItemDownloadedButton(item: item)
|
||||
: isItemDownloading
|
||||
return isItemDownloading
|
||||
? ItemCurrentlyInDownloadQueue(
|
||||
item: item,
|
||||
)
|
||||
|
|
@ -248,9 +248,14 @@ class ItemCurrentlyInDownloadQueue extends HookConsumerWidget {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final progress = ref.watch(downloadProgressProvider(item.id));
|
||||
final updatesStream = useStream(ref.watch(downloadManagerProvider).taskUpdateStream);
|
||||
final progress =
|
||||
ref.watch(itemDownloadProgressProvider(item.id)).valueOrNull;
|
||||
|
||||
if (progress == 1) {
|
||||
return AlreadyItemDownloadedButton(item: item);
|
||||
}
|
||||
|
||||
const shimmerDuration = Duration(milliseconds: 1000);
|
||||
return Stack(
|
||||
alignment: Alignment.center,
|
||||
children: [
|
||||
|
|
@ -260,19 +265,22 @@ class ItemCurrentlyInDownloadQueue extends HookConsumerWidget {
|
|||
),
|
||||
const Icon(
|
||||
Icons.download,
|
||||
// color: Theme.of(context).progressIndicatorTheme.color,
|
||||
)
|
||||
.animate(
|
||||
onPlay: (controller) => controller.repeat(),
|
||||
)
|
||||
.fade(
|
||||
begin: 0.5,
|
||||
duration: shimmerDuration,
|
||||
end: 1,
|
||||
duration: 1.seconds,
|
||||
begin: 0.6,
|
||||
curve: Curves.linearToEaseOut,
|
||||
)
|
||||
.fade(
|
||||
duration: shimmerDuration,
|
||||
end: 0.7,
|
||||
begin: 1,
|
||||
end: 0.5,
|
||||
duration: 1.seconds,
|
||||
curve: Curves.easeInToLinear,
|
||||
),
|
||||
],
|
||||
);
|
||||
|
|
@ -520,7 +528,7 @@ Future<void> libraryItemPlayButtonOnPressed({
|
|||
final downloadManager = ref.watch(simpleDownloadManagerProvider);
|
||||
final libItem =
|
||||
await ref.read(libraryItemProvider(book.libraryItemId).future);
|
||||
final downloadedUris = await downloadManager.getDownloadedFiles(libItem);
|
||||
final downloadedUris = await downloadManager.getDownloadedFilesUri(libItem);
|
||||
setSourceFuture = player.setSourceAudiobook(
|
||||
book,
|
||||
initialPosition: userMediaProgress?.currentTime,
|
||||
|
|
|
|||
10
lib/shared/extensions/item_files.dart
Normal file
10
lib/shared/extensions/item_files.dart
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
import 'package:shelfsdk/audiobookshelf_api.dart';
|
||||
|
||||
extension TotalSize on LibraryItemExpanded {
|
||||
int get totalSize {
|
||||
return libraryFiles.fold(
|
||||
0,
|
||||
(previousValue, element) => previousValue + element.metadata.size,
|
||||
);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue