mirror of
https://github.com/gabehf/Fladder.git
synced 2026-03-07 21:48:14 -08:00
fix: Downloads resetting with multiple active downloads (#606)
feat: Add sync count icon to menu bars
This commit is contained in:
parent
493f40645c
commit
d8f613de07
8 changed files with 105 additions and 67 deletions
|
|
@ -23,6 +23,8 @@ class DownloadStream {
|
|||
|
||||
bool get hasDownload => progress != -1.0 && status != dl.TaskStatus.notFound && status != dl.TaskStatus.complete;
|
||||
|
||||
bool get isEnqueuedOrDownloading => status == dl.TaskStatus.enqueued || status == dl.TaskStatus.running;
|
||||
|
||||
DownloadStream copyWith({
|
||||
String? id,
|
||||
dl.DownloadTask? task,
|
||||
|
|
|
|||
|
|
@ -44,6 +44,11 @@ class BackgroundDownloader extends _$BackgroundDownloader {
|
|||
|
||||
if (status == TaskStatus.complete || status == TaskStatus.canceled) {
|
||||
ref.read(downloadTasksProvider(update.task.taskId).notifier).update((state) => DownloadStream.empty());
|
||||
ref
|
||||
.read(activeDownloadTasksProvider.notifier)
|
||||
.update((state) => state.where((element) => element.taskId != update.task.taskId).toList());
|
||||
|
||||
ref.read(syncProvider.notifier).cleanupTemporaryFiles();
|
||||
}
|
||||
case TaskProgressUpdate():
|
||||
final progress = update.progress;
|
||||
|
|
|
|||
|
|
@ -54,9 +54,10 @@ class SyncDownloadStatus extends _$SyncDownloadStatus {
|
|||
if (childItem.videoFile.existsSync()) {
|
||||
fullySyncedChildren++;
|
||||
}
|
||||
if (downloadStream.hasDownload) {
|
||||
if (downloadStream.isEnqueuedOrDownloading) {
|
||||
downloadCount++;
|
||||
fullProgress += downloadStream.progress;
|
||||
fullProgress += downloadStream.progress.clamp(0.0, 1.0);
|
||||
|
||||
mainStream = mainStream.copyWith(
|
||||
status: mainStream.status != TaskStatus.running ? downloadStream.status : mainStream.status,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ import 'dart:convert';
|
|||
import 'dart:developer';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:fladder/util/string_extensions.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart' hide ConnectionState;
|
||||
|
||||
|
|
@ -42,11 +41,16 @@ import 'package:fladder/providers/user_provider.dart';
|
|||
import 'package:fladder/screens/shared/fladder_snackbar.dart';
|
||||
import 'package:fladder/util/duration_extensions.dart';
|
||||
import 'package:fladder/util/localization_helper.dart';
|
||||
import 'package:fladder/util/string_extensions.dart';
|
||||
|
||||
final syncProvider = StateNotifierProvider<SyncNotifier, SyncSettingsModel>((ref) => throw UnimplementedError());
|
||||
|
||||
final downloadTasksProvider = StateProvider.family<DownloadStream, String?>((ref, id) => DownloadStream.empty());
|
||||
|
||||
final activeDownloadTasksProvider = StateProvider<List<DownloadTask>>((ref) {
|
||||
return [];
|
||||
});
|
||||
|
||||
class SyncNotifier extends StateNotifier<SyncSettingsModel> {
|
||||
SyncNotifier(this.ref, this.mobileDirectory) : super(SyncSettingsModel()) {
|
||||
_init();
|
||||
|
|
@ -130,6 +134,9 @@ class SyncNotifier extends StateNotifier<SyncSettingsModel> {
|
|||
}
|
||||
|
||||
Future<void> cleanupTemporaryFiles() async {
|
||||
final activeDownloads = ref.read(activeDownloadTasksProvider);
|
||||
if (activeDownloads.isNotEmpty) return;
|
||||
|
||||
// List of directories to check
|
||||
final directories = [
|
||||
//Desktop directory
|
||||
|
|
@ -518,6 +525,11 @@ class SyncNotifier extends StateNotifier<SyncSettingsModel> {
|
|||
allowPause: true,
|
||||
);
|
||||
|
||||
ref.read(activeDownloadTasksProvider.notifier).update((state) {
|
||||
final existingTasks = state.where((element) => element.taskId != downloadTask.taskId).toList();
|
||||
return [...existingTasks, downloadTask];
|
||||
});
|
||||
|
||||
final defaultDownloadStream = DownloadStream(id: syncItem.id, task: downloadTask, status: TaskStatus.enqueued);
|
||||
ref.read(downloadTasksProvider(syncItem.id).notifier).update((state) => defaultDownloadStream);
|
||||
return await ref.read(backgroundDownloaderProvider).enqueue(downloadTask);
|
||||
|
|
@ -621,7 +633,7 @@ extension SyncNotifierHelpers on SyncNotifier {
|
|||
if (parent == null) {
|
||||
await _db.insertItem(syncItem);
|
||||
}
|
||||
|
||||
|
||||
return syncItem.copyWith(
|
||||
fileSize: response.mediaSources?.firstOrNull?.size ?? 0,
|
||||
syncing: false,
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import 'package:window_manager/window_manager.dart';
|
|||
|
||||
import 'package:fladder/models/settings/client_settings_model.dart';
|
||||
import 'package:fladder/providers/settings/client_settings_provider.dart';
|
||||
import 'package:fladder/providers/sync_provider.dart';
|
||||
import 'package:fladder/providers/user_provider.dart';
|
||||
import 'package:fladder/routes/auto_router.gr.dart';
|
||||
import 'package:fladder/screens/shared/fladder_snackbar.dart';
|
||||
|
|
@ -101,6 +102,19 @@ class HomeScreen extends ConsumerWidget {
|
|||
return DestinationModel(
|
||||
label: context.localized.navigationSync,
|
||||
icon: Icon(e.icon),
|
||||
badge: Consumer(
|
||||
builder: (context, ref, child) {
|
||||
final length = ref.watch(activeDownloadTasksProvider.select((value) => value.length));
|
||||
return length != 0
|
||||
? CircleAvatar(
|
||||
radius: 10,
|
||||
child: FittedBox(
|
||||
child: Text(length.toString()),
|
||||
),
|
||||
)
|
||||
: const SizedBox.shrink();
|
||||
},
|
||||
),
|
||||
selectedIcon: Icon(e.selectedIcon),
|
||||
route: const SyncedRoute(),
|
||||
action: () => e.navigate(context),
|
||||
|
|
|
|||
|
|
@ -12,9 +12,8 @@ class DestinationModel {
|
|||
final PageRouteInfo? route;
|
||||
final Function()? action;
|
||||
final String? tooltip;
|
||||
final Badge? badge;
|
||||
final Widget? badge;
|
||||
final AdaptiveFab? floatingActionButton;
|
||||
// final FloatingActionButton? floatingActionButton;
|
||||
|
||||
DestinationModel({
|
||||
required this.label,
|
||||
|
|
@ -25,21 +24,10 @@ class DestinationModel {
|
|||
this.tooltip,
|
||||
this.badge,
|
||||
this.floatingActionButton,
|
||||
}) : assert(
|
||||
badge == null || icon == null,
|
||||
'Only one of icon or badge should be provided, not both.',
|
||||
);
|
||||
});
|
||||
|
||||
/// Converts this [DestinationModel] to a [NavigationRailDestination] used in a [NavigationRail].
|
||||
NavigationRailDestination toNavigationRailDestination({EdgeInsets? padding}) {
|
||||
if (badge != null) {
|
||||
return NavigationRailDestination(
|
||||
icon: badge!,
|
||||
label: Text(label),
|
||||
selectedIcon: badge!,
|
||||
padding: padding,
|
||||
);
|
||||
}
|
||||
return NavigationRailDestination(
|
||||
icon: icon!,
|
||||
label: Text(label),
|
||||
|
|
@ -50,13 +38,6 @@ class DestinationModel {
|
|||
|
||||
/// Converts this [DestinationModel] to a [NavigationDrawerDestination] used in a [NavigationDrawer].
|
||||
NavigationDrawerDestination toNavigationDrawerDestination() {
|
||||
if (badge != null) {
|
||||
return NavigationDrawerDestination(
|
||||
icon: badge!,
|
||||
label: Text(label),
|
||||
selectedIcon: badge!,
|
||||
);
|
||||
}
|
||||
return NavigationDrawerDestination(
|
||||
icon: icon!,
|
||||
label: Text(label),
|
||||
|
|
@ -66,13 +47,6 @@ class DestinationModel {
|
|||
|
||||
/// Converts this [DestinationModel] to a [NavigationDestination] used in a [BottomNavigationBar].
|
||||
NavigationDestination toNavigationDestination() {
|
||||
if (badge != null) {
|
||||
return NavigationDestination(
|
||||
icon: badge!,
|
||||
label: label,
|
||||
selectedIcon: badge!,
|
||||
);
|
||||
}
|
||||
return NavigationDestination(
|
||||
icon: icon!,
|
||||
label: label,
|
||||
|
|
@ -87,6 +61,7 @@ class DestinationModel {
|
|||
label: label,
|
||||
selected: selected,
|
||||
navFocusNode: navFocusNode,
|
||||
badge: badge,
|
||||
onPressed: action,
|
||||
horizontal: horizontal,
|
||||
expanded: expanded,
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ class NavigationButton extends ConsumerStatefulWidget {
|
|||
final String? label;
|
||||
final Widget selectedIcon;
|
||||
final Widget icon;
|
||||
final Widget? badge;
|
||||
final bool navFocusNode;
|
||||
final bool horizontal;
|
||||
final bool expanded;
|
||||
|
|
@ -23,6 +24,7 @@ class NavigationButton extends ConsumerStatefulWidget {
|
|||
required this.label,
|
||||
required this.selectedIcon,
|
||||
required this.icon,
|
||||
this.badge,
|
||||
this.navFocusNode = false,
|
||||
this.horizontal = false,
|
||||
this.expanded = false,
|
||||
|
|
@ -95,9 +97,19 @@ class _NavigationButtonState extends ConsumerState<NavigationButton> {
|
|||
),
|
||||
),
|
||||
widget.customIcon ??
|
||||
AnimatedSwitcher(
|
||||
duration: widget.duration,
|
||||
child: widget.selected ? widget.selectedIcon : widget.icon,
|
||||
Stack(
|
||||
alignment: Alignment.center,
|
||||
children: [
|
||||
AnimatedSwitcher(
|
||||
duration: widget.duration,
|
||||
child: widget.selected ? widget.selectedIcon : widget.icon,
|
||||
),
|
||||
if (widget.badge != null && !widget.expanded)
|
||||
Transform.translate(
|
||||
offset: const Offset(8, -8),
|
||||
child: widget.badge,
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(width: 6),
|
||||
if (widget.horizontal && widget.expanded) ...[
|
||||
|
|
@ -105,10 +117,17 @@ class _NavigationButtonState extends ConsumerState<NavigationButton> {
|
|||
Expanded(
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints(minWidth: 80),
|
||||
child: Text(
|
||||
widget.label!,
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
widget.label!,
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
if (widget.badge != null) widget.badge!,
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
@ -137,9 +156,19 @@ class _NavigationButtonState extends ConsumerState<NavigationButton> {
|
|||
spacing: 8,
|
||||
children: [
|
||||
widget.customIcon ??
|
||||
AnimatedSwitcher(
|
||||
duration: widget.duration,
|
||||
child: widget.selected ? widget.selectedIcon : widget.icon,
|
||||
Stack(
|
||||
alignment: Alignment.center,
|
||||
children: [
|
||||
AnimatedSwitcher(
|
||||
duration: widget.duration,
|
||||
child: widget.selected ? widget.selectedIcon : widget.icon,
|
||||
),
|
||||
if (widget.badge != null && !widget.expanded)
|
||||
Transform.translate(
|
||||
offset: const Offset(8, -8),
|
||||
child: widget.badge,
|
||||
),
|
||||
],
|
||||
),
|
||||
if (widget.label != null && widget.horizontal && widget.expanded)
|
||||
Flexible(child: Text(widget.label!))
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue