feat: Add max concurrent downloads to settings (#347)

Co-authored-by: PartyDonut <PartyDonut@users.noreply.github.com>
This commit is contained in:
PartyDonut 2025-05-18 10:14:23 +02:00 committed by GitHub
parent 947da2390f
commit 8acd880329
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 110 additions and 20 deletions

View file

@ -1199,5 +1199,7 @@
"example": "1" "example": "1"
} }
} }
} },
"maxConcurrentDownloadsTitle": "Max concurrent downloads",
"maxConcurrentDownloadsDesc": "Sets the maximum number of downloads that can run at the same time. Set to 0 to disable the limit."
} }

View file

@ -32,6 +32,7 @@ class ClientSettingsModel with _$ClientSettingsModel {
@Default(false) bool mouseDragSupport, @Default(false) bool mouseDragSupport,
@Default(true) bool requireWifi, @Default(true) bool requireWifi,
@Default(false) bool showAllCollectionTypes, @Default(false) bool showAllCollectionTypes,
@Default(2) int maxConcurrentDownloads,
@Default(DynamicSchemeVariant.tonalSpot) DynamicSchemeVariant schemeVariant, @Default(DynamicSchemeVariant.tonalSpot) DynamicSchemeVariant schemeVariant,
int? libraryPageSize, int? libraryPageSize,
}) = _ClientSettingsModel; }) = _ClientSettingsModel;

View file

@ -38,6 +38,7 @@ mixin _$ClientSettingsModel {
bool get mouseDragSupport => throw _privateConstructorUsedError; bool get mouseDragSupport => throw _privateConstructorUsedError;
bool get requireWifi => throw _privateConstructorUsedError; bool get requireWifi => throw _privateConstructorUsedError;
bool get showAllCollectionTypes => throw _privateConstructorUsedError; bool get showAllCollectionTypes => throw _privateConstructorUsedError;
int get maxConcurrentDownloads => throw _privateConstructorUsedError;
DynamicSchemeVariant get schemeVariant => throw _privateConstructorUsedError; DynamicSchemeVariant get schemeVariant => throw _privateConstructorUsedError;
int? get libraryPageSize => throw _privateConstructorUsedError; int? get libraryPageSize => throw _privateConstructorUsedError;
@ -75,6 +76,7 @@ abstract class $ClientSettingsModelCopyWith<$Res> {
bool mouseDragSupport, bool mouseDragSupport,
bool requireWifi, bool requireWifi,
bool showAllCollectionTypes, bool showAllCollectionTypes,
int maxConcurrentDownloads,
DynamicSchemeVariant schemeVariant, DynamicSchemeVariant schemeVariant,
int? libraryPageSize}); int? libraryPageSize});
} }
@ -111,6 +113,7 @@ class _$ClientSettingsModelCopyWithImpl<$Res, $Val extends ClientSettingsModel>
Object? mouseDragSupport = null, Object? mouseDragSupport = null,
Object? requireWifi = null, Object? requireWifi = null,
Object? showAllCollectionTypes = null, Object? showAllCollectionTypes = null,
Object? maxConcurrentDownloads = null,
Object? schemeVariant = null, Object? schemeVariant = null,
Object? libraryPageSize = freezed, Object? libraryPageSize = freezed,
}) { }) {
@ -183,6 +186,10 @@ class _$ClientSettingsModelCopyWithImpl<$Res, $Val extends ClientSettingsModel>
? _value.showAllCollectionTypes ? _value.showAllCollectionTypes
: showAllCollectionTypes // ignore: cast_nullable_to_non_nullable : showAllCollectionTypes // ignore: cast_nullable_to_non_nullable
as bool, as bool,
maxConcurrentDownloads: null == maxConcurrentDownloads
? _value.maxConcurrentDownloads
: maxConcurrentDownloads // ignore: cast_nullable_to_non_nullable
as int,
schemeVariant: null == schemeVariant schemeVariant: null == schemeVariant
? _value.schemeVariant ? _value.schemeVariant
: schemeVariant // ignore: cast_nullable_to_non_nullable : schemeVariant // ignore: cast_nullable_to_non_nullable
@ -221,6 +228,7 @@ abstract class _$$ClientSettingsModelImplCopyWith<$Res>
bool mouseDragSupport, bool mouseDragSupport,
bool requireWifi, bool requireWifi,
bool showAllCollectionTypes, bool showAllCollectionTypes,
int maxConcurrentDownloads,
DynamicSchemeVariant schemeVariant, DynamicSchemeVariant schemeVariant,
int? libraryPageSize}); int? libraryPageSize});
} }
@ -255,6 +263,7 @@ class __$$ClientSettingsModelImplCopyWithImpl<$Res>
Object? mouseDragSupport = null, Object? mouseDragSupport = null,
Object? requireWifi = null, Object? requireWifi = null,
Object? showAllCollectionTypes = null, Object? showAllCollectionTypes = null,
Object? maxConcurrentDownloads = null,
Object? schemeVariant = null, Object? schemeVariant = null,
Object? libraryPageSize = freezed, Object? libraryPageSize = freezed,
}) { }) {
@ -327,6 +336,10 @@ class __$$ClientSettingsModelImplCopyWithImpl<$Res>
? _value.showAllCollectionTypes ? _value.showAllCollectionTypes
: showAllCollectionTypes // ignore: cast_nullable_to_non_nullable : showAllCollectionTypes // ignore: cast_nullable_to_non_nullable
as bool, as bool,
maxConcurrentDownloads: null == maxConcurrentDownloads
? _value.maxConcurrentDownloads
: maxConcurrentDownloads // ignore: cast_nullable_to_non_nullable
as int,
schemeVariant: null == schemeVariant schemeVariant: null == schemeVariant
? _value.schemeVariant ? _value.schemeVariant
: schemeVariant // ignore: cast_nullable_to_non_nullable : schemeVariant // ignore: cast_nullable_to_non_nullable
@ -361,6 +374,7 @@ class _$ClientSettingsModelImpl extends _ClientSettingsModel
this.mouseDragSupport = false, this.mouseDragSupport = false,
this.requireWifi = true, this.requireWifi = true,
this.showAllCollectionTypes = false, this.showAllCollectionTypes = false,
this.maxConcurrentDownloads = 2,
this.schemeVariant = DynamicSchemeVariant.tonalSpot, this.schemeVariant = DynamicSchemeVariant.tonalSpot,
this.libraryPageSize}) this.libraryPageSize})
: super._(); : super._();
@ -418,13 +432,16 @@ class _$ClientSettingsModelImpl extends _ClientSettingsModel
final bool showAllCollectionTypes; final bool showAllCollectionTypes;
@override @override
@JsonKey() @JsonKey()
final int maxConcurrentDownloads;
@override
@JsonKey()
final DynamicSchemeVariant schemeVariant; final DynamicSchemeVariant schemeVariant;
@override @override
final int? libraryPageSize; final int? libraryPageSize;
@override @override
String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) { String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) {
return 'ClientSettingsModel(syncPath: $syncPath, position: $position, size: $size, timeOut: $timeOut, nextUpDateCutoff: $nextUpDateCutoff, themeMode: $themeMode, themeColor: $themeColor, amoledBlack: $amoledBlack, blurPlaceHolders: $blurPlaceHolders, blurUpcomingEpisodes: $blurUpcomingEpisodes, selectedLocale: $selectedLocale, enableMediaKeys: $enableMediaKeys, posterSize: $posterSize, pinchPosterZoom: $pinchPosterZoom, mouseDragSupport: $mouseDragSupport, requireWifi: $requireWifi, showAllCollectionTypes: $showAllCollectionTypes, schemeVariant: $schemeVariant, libraryPageSize: $libraryPageSize)'; return 'ClientSettingsModel(syncPath: $syncPath, position: $position, size: $size, timeOut: $timeOut, nextUpDateCutoff: $nextUpDateCutoff, themeMode: $themeMode, themeColor: $themeColor, amoledBlack: $amoledBlack, blurPlaceHolders: $blurPlaceHolders, blurUpcomingEpisodes: $blurUpcomingEpisodes, selectedLocale: $selectedLocale, enableMediaKeys: $enableMediaKeys, posterSize: $posterSize, pinchPosterZoom: $pinchPosterZoom, mouseDragSupport: $mouseDragSupport, requireWifi: $requireWifi, showAllCollectionTypes: $showAllCollectionTypes, maxConcurrentDownloads: $maxConcurrentDownloads, schemeVariant: $schemeVariant, libraryPageSize: $libraryPageSize)';
} }
@override @override
@ -450,6 +467,8 @@ class _$ClientSettingsModelImpl extends _ClientSettingsModel
..add(DiagnosticsProperty('requireWifi', requireWifi)) ..add(DiagnosticsProperty('requireWifi', requireWifi))
..add( ..add(
DiagnosticsProperty('showAllCollectionTypes', showAllCollectionTypes)) DiagnosticsProperty('showAllCollectionTypes', showAllCollectionTypes))
..add(
DiagnosticsProperty('maxConcurrentDownloads', maxConcurrentDownloads))
..add(DiagnosticsProperty('schemeVariant', schemeVariant)) ..add(DiagnosticsProperty('schemeVariant', schemeVariant))
..add(DiagnosticsProperty('libraryPageSize', libraryPageSize)); ..add(DiagnosticsProperty('libraryPageSize', libraryPageSize));
} }
@ -491,6 +510,8 @@ class _$ClientSettingsModelImpl extends _ClientSettingsModel
other.requireWifi == requireWifi) && other.requireWifi == requireWifi) &&
(identical(other.showAllCollectionTypes, showAllCollectionTypes) || (identical(other.showAllCollectionTypes, showAllCollectionTypes) ||
other.showAllCollectionTypes == showAllCollectionTypes) && other.showAllCollectionTypes == showAllCollectionTypes) &&
(identical(other.maxConcurrentDownloads, maxConcurrentDownloads) ||
other.maxConcurrentDownloads == maxConcurrentDownloads) &&
(identical(other.schemeVariant, schemeVariant) || (identical(other.schemeVariant, schemeVariant) ||
other.schemeVariant == schemeVariant) && other.schemeVariant == schemeVariant) &&
(identical(other.libraryPageSize, libraryPageSize) || (identical(other.libraryPageSize, libraryPageSize) ||
@ -518,6 +539,7 @@ class _$ClientSettingsModelImpl extends _ClientSettingsModel
mouseDragSupport, mouseDragSupport,
requireWifi, requireWifi,
showAllCollectionTypes, showAllCollectionTypes,
maxConcurrentDownloads,
schemeVariant, schemeVariant,
libraryPageSize libraryPageSize
]); ]);
@ -558,6 +580,7 @@ abstract class _ClientSettingsModel extends ClientSettingsModel {
final bool mouseDragSupport, final bool mouseDragSupport,
final bool requireWifi, final bool requireWifi,
final bool showAllCollectionTypes, final bool showAllCollectionTypes,
final int maxConcurrentDownloads,
final DynamicSchemeVariant schemeVariant, final DynamicSchemeVariant schemeVariant,
final int? libraryPageSize}) = _$ClientSettingsModelImpl; final int? libraryPageSize}) = _$ClientSettingsModelImpl;
_ClientSettingsModel._() : super._(); _ClientSettingsModel._() : super._();
@ -601,6 +624,8 @@ abstract class _ClientSettingsModel extends ClientSettingsModel {
@override @override
bool get showAllCollectionTypes; bool get showAllCollectionTypes;
@override @override
int get maxConcurrentDownloads;
@override
DynamicSchemeVariant get schemeVariant; DynamicSchemeVariant get schemeVariant;
@override @override
int? get libraryPageSize; int? get libraryPageSize;

View file

@ -36,6 +36,8 @@ _$ClientSettingsModelImpl _$$ClientSettingsModelImplFromJson(
mouseDragSupport: json['mouseDragSupport'] as bool? ?? false, mouseDragSupport: json['mouseDragSupport'] as bool? ?? false,
requireWifi: json['requireWifi'] as bool? ?? true, requireWifi: json['requireWifi'] as bool? ?? true,
showAllCollectionTypes: json['showAllCollectionTypes'] as bool? ?? false, showAllCollectionTypes: json['showAllCollectionTypes'] as bool? ?? false,
maxConcurrentDownloads:
(json['maxConcurrentDownloads'] as num?)?.toInt() ?? 2,
schemeVariant: $enumDecodeNullable( schemeVariant: $enumDecodeNullable(
_$DynamicSchemeVariantEnumMap, json['schemeVariant']) ?? _$DynamicSchemeVariantEnumMap, json['schemeVariant']) ??
DynamicSchemeVariant.tonalSpot, DynamicSchemeVariant.tonalSpot,
@ -62,6 +64,7 @@ Map<String, dynamic> _$$ClientSettingsModelImplToJson(
'mouseDragSupport': instance.mouseDragSupport, 'mouseDragSupport': instance.mouseDragSupport,
'requireWifi': instance.requireWifi, 'requireWifi': instance.requireWifi,
'showAllCollectionTypes': instance.showAllCollectionTypes, 'showAllCollectionTypes': instance.showAllCollectionTypes,
'maxConcurrentDownloads': instance.maxConcurrentDownloads,
'schemeVariant': _$DynamicSchemeVariantEnumMap[instance.schemeVariant]!, 'schemeVariant': _$DynamicSchemeVariantEnumMap[instance.schemeVariant]!,
'libraryPageSize': instance.libraryPageSize, 'libraryPageSize': instance.libraryPageSize,
}; };

View file

@ -1,17 +1,55 @@
import 'package:background_downloader/background_downloader.dart'; import 'package:background_downloader/background_downloader.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:fladder/providers/settings/client_settings_provider.dart';
part 'background_download_provider.g.dart'; part 'background_download_provider.g.dart';
@Riverpod(keepAlive: true) @Riverpod(keepAlive: true)
FileDownloader backgroundDownloader(Ref ref) { class BackgroundDownloader extends _$BackgroundDownloader {
return FileDownloader() @override
..trackTasks() FileDownloader build() {
..configureNotification( final maxDownloads = ref.read(clientSettingsProvider.select((value) => value.maxConcurrentDownloads));
running: const TaskNotification('Downloading', 'file: {filename}'), return FileDownloader()
complete: const TaskNotification('Download finished', 'file: {filename}'), ..configure(
paused: const TaskNotification('Download paused', 'file: {filename}'), globalConfig: maxDownloads == 0
progressBar: true, ? ("", "")
: (
Config.holdingQueue,
(
//maxConcurrent
maxDownloads,
//maxConcurrentByHost
maxDownloads,
//maxConcurrentByGroup
maxDownloads,
),
),
)
..trackTasks()
..configureNotification(
running: const TaskNotification('Downloading', 'file: {filename}'),
complete: const TaskNotification('Download finished', 'file: {filename}'),
paused: const TaskNotification('Download paused', 'file: {filename}'),
progressBar: true,
);
}
void setMaxConcurrent(int value) {
state.configure(
globalConfig: value == 0
? ("", "")
: (
Config.holdingQueue,
(
//maxConcurrent
value,
//maxConcurrentByHost
value,
//maxConcurrentByGroup
value,
),
),
); );
}
} }

View file

@ -7,12 +7,13 @@ part of 'background_download_provider.dart';
// ************************************************************************** // **************************************************************************
String _$backgroundDownloaderHash() => String _$backgroundDownloaderHash() =>
r'997d9f4ba79dd0d9d30d5f283b36d5280d10dfaa'; r'df72b6338a8e80178935985ba17c43bf720f4522';
/// See also [backgroundDownloader]. /// See also [BackgroundDownloader].
@ProviderFor(backgroundDownloader) @ProviderFor(BackgroundDownloader)
final backgroundDownloaderProvider = Provider<FileDownloader>.internal( final backgroundDownloaderProvider =
backgroundDownloader, NotifierProvider<BackgroundDownloader, FileDownloader>.internal(
BackgroundDownloader.new,
name: r'backgroundDownloaderProvider', name: r'backgroundDownloaderProvider',
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
? null ? null
@ -21,8 +22,6 @@ final backgroundDownloaderProvider = Provider<FileDownloader>.internal(
allTransitiveDependencies: null, allTransitiveDependencies: null,
); );
@Deprecated('Will be removed in 3.0. Use Ref instead') typedef _$BackgroundDownloader = Notifier<FileDownloader>;
// ignore: unused_element
typedef BackgroundDownloaderRef = ProviderRef<FileDownloader>;
// 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, deprecated_member_use_from_same_package // ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package

View file

@ -1,16 +1,18 @@
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:iconsax_plus/iconsax_plus.dart';
import 'package:file_picker/file_picker.dart'; import 'package:file_picker/file_picker.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:iconsax_plus/iconsax_plus.dart';
import 'package:fladder/providers/settings/client_settings_provider.dart'; import 'package:fladder/providers/settings/client_settings_provider.dart';
import 'package:fladder/providers/sync/background_download_provider.dart';
import 'package:fladder/providers/sync_provider.dart'; import 'package:fladder/providers/sync_provider.dart';
import 'package:fladder/providers/user_provider.dart'; import 'package:fladder/providers/user_provider.dart';
import 'package:fladder/screens/settings/settings_list_tile.dart'; import 'package:fladder/screens/settings/settings_list_tile.dart';
import 'package:fladder/screens/settings/widgets/settings_label_divider.dart'; import 'package:fladder/screens/settings/widgets/settings_label_divider.dart';
import 'package:fladder/screens/shared/default_alert_dialog.dart'; import 'package:fladder/screens/shared/default_alert_dialog.dart';
import 'package:fladder/screens/shared/input_fields.dart';
import 'package:fladder/util/adaptive_layout.dart'; import 'package:fladder/util/adaptive_layout.dart';
import 'package:fladder/util/localization_helper.dart'; import 'package:fladder/util/localization_helper.dart';
import 'package:fladder/util/size_formatting.dart'; import 'package:fladder/util/size_formatting.dart';
@ -116,6 +118,26 @@ List<Widget> buildClientSettingsDownload(BuildContext context, WidgetRef ref, Fu
onChanged: (value) => ref.read(clientSettingsProvider.notifier).setRequireWifi(value), onChanged: (value) => ref.read(clientSettingsProvider.notifier).setRequireWifi(value),
), ),
), ),
SettingsListTile(
label: Text(context.localized.maxConcurrentDownloadsTitle),
subLabel: Text(context.localized.maxConcurrentDownloadsDesc),
trailing: SizedBox(
width: 100,
child: IntInputField(
controller: TextEditingController(text: clientSettings.maxConcurrentDownloads.toString()),
onSubmitted: (value) {
if (value != null) {
ref.read(clientSettingsProvider.notifier).update(
(current) => current.copyWith(
maxConcurrentDownloads: value,
),
);
ref.read(backgroundDownloaderProvider.notifier).setMaxConcurrent(value);
}
},
)),
),
const Divider(), const Divider(),
], ],
]; ];