mirror of
https://github.com/zarzet/SpotiFLAC-Mobile.git
synced 2026-07-26 14:01:03 +02:00
feat(downloads): support up to 3 concurrent downloads
The Dart queue loop was already built around an activeDownloads map and per-item progress tracking but was gated to one download at a time. Add a concurrentDownloads setting (1-3, default 1) exposed in Download Settings > Performance, and let the scheduler keep up to that many items in flight. The experimental Android native worker is still strictly sequential, so it is skipped in favor of the Dart queue while concurrency is enabled.
This commit is contained in:
@@ -3074,6 +3074,30 @@ abstract class AppLocalizations {
|
||||
/// **'Choose which network to use for downloads. When set to WiFi Only, downloads will pause on mobile data.'**
|
||||
String get settingsDownloadNetworkSubtitle;
|
||||
|
||||
/// Setting title - how many tracks download at the same time
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Concurrent downloads'**
|
||||
String get settingsConcurrentDownloads;
|
||||
|
||||
/// Subtitle explaining the concurrent downloads picker
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Downloading several tracks at once is faster, but some providers may rate-limit parallel requests.'**
|
||||
String get settingsConcurrentDownloadsSubtitle;
|
||||
|
||||
/// Concurrent downloads option - sequential
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'1 track at a time'**
|
||||
String get concurrentDownloadsOne;
|
||||
|
||||
/// Concurrent downloads option - parallel
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Up to {count} tracks at once'**
|
||||
String concurrentDownloadsCount(int count);
|
||||
|
||||
/// Album folder option
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
|
||||
@@ -1658,6 +1658,21 @@ class AppLocalizationsAr extends AppLocalizations {
|
||||
String get settingsDownloadNetworkSubtitle =>
|
||||
'Choose which network to use for downloads. When set to WiFi Only, downloads will pause on mobile data.';
|
||||
|
||||
@override
|
||||
String get settingsConcurrentDownloads => 'Concurrent downloads';
|
||||
|
||||
@override
|
||||
String get settingsConcurrentDownloadsSubtitle =>
|
||||
'Downloading several tracks at once is faster, but some providers may rate-limit parallel requests.';
|
||||
|
||||
@override
|
||||
String get concurrentDownloadsOne => '1 track at a time';
|
||||
|
||||
@override
|
||||
String concurrentDownloadsCount(int count) {
|
||||
return 'Up to $count tracks at once';
|
||||
}
|
||||
|
||||
@override
|
||||
String get albumFolderArtistAlbum => 'Artist / Album';
|
||||
|
||||
|
||||
@@ -1683,6 +1683,21 @@ class AppLocalizationsDe extends AppLocalizations {
|
||||
String get settingsDownloadNetworkSubtitle =>
|
||||
'Wähle aus, welches Netzwerk für Downloads verwendet werden soll. Wenn nur WLAN aktiviert wird, werden Downloads auf mobilen Daten angehalten.';
|
||||
|
||||
@override
|
||||
String get settingsConcurrentDownloads => 'Concurrent downloads';
|
||||
|
||||
@override
|
||||
String get settingsConcurrentDownloadsSubtitle =>
|
||||
'Downloading several tracks at once is faster, but some providers may rate-limit parallel requests.';
|
||||
|
||||
@override
|
||||
String get concurrentDownloadsOne => '1 track at a time';
|
||||
|
||||
@override
|
||||
String concurrentDownloadsCount(int count) {
|
||||
return 'Up to $count tracks at once';
|
||||
}
|
||||
|
||||
@override
|
||||
String get albumFolderArtistAlbum => 'Künstler/Album';
|
||||
|
||||
|
||||
@@ -1658,6 +1658,21 @@ class AppLocalizationsEn extends AppLocalizations {
|
||||
String get settingsDownloadNetworkSubtitle =>
|
||||
'Choose which network to use for downloads. When set to WiFi Only, downloads will pause on mobile data.';
|
||||
|
||||
@override
|
||||
String get settingsConcurrentDownloads => 'Concurrent downloads';
|
||||
|
||||
@override
|
||||
String get settingsConcurrentDownloadsSubtitle =>
|
||||
'Downloading several tracks at once is faster, but some providers may rate-limit parallel requests.';
|
||||
|
||||
@override
|
||||
String get concurrentDownloadsOne => '1 track at a time';
|
||||
|
||||
@override
|
||||
String concurrentDownloadsCount(int count) {
|
||||
return 'Up to $count tracks at once';
|
||||
}
|
||||
|
||||
@override
|
||||
String get albumFolderArtistAlbum => 'Artist / Album';
|
||||
|
||||
|
||||
@@ -1658,6 +1658,21 @@ class AppLocalizationsEs extends AppLocalizations {
|
||||
String get settingsDownloadNetworkSubtitle =>
|
||||
'Choose which network to use for downloads. When set to WiFi Only, downloads will pause on mobile data.';
|
||||
|
||||
@override
|
||||
String get settingsConcurrentDownloads => 'Concurrent downloads';
|
||||
|
||||
@override
|
||||
String get settingsConcurrentDownloadsSubtitle =>
|
||||
'Downloading several tracks at once is faster, but some providers may rate-limit parallel requests.';
|
||||
|
||||
@override
|
||||
String get concurrentDownloadsOne => '1 track at a time';
|
||||
|
||||
@override
|
||||
String concurrentDownloadsCount(int count) {
|
||||
return 'Up to $count tracks at once';
|
||||
}
|
||||
|
||||
@override
|
||||
String get albumFolderArtistAlbum => 'Artist / Album';
|
||||
|
||||
|
||||
@@ -1706,6 +1706,21 @@ class AppLocalizationsFr extends AppLocalizations {
|
||||
String get settingsDownloadNetworkSubtitle =>
|
||||
'Choisissez le réseau à utiliser pour les téléchargements. Si vous sélectionnez « Wi-Fi uniquement », les téléchargements seront interrompus lorsque vous utilisez les données mobiles.';
|
||||
|
||||
@override
|
||||
String get settingsConcurrentDownloads => 'Concurrent downloads';
|
||||
|
||||
@override
|
||||
String get settingsConcurrentDownloadsSubtitle =>
|
||||
'Downloading several tracks at once is faster, but some providers may rate-limit parallel requests.';
|
||||
|
||||
@override
|
||||
String get concurrentDownloadsOne => '1 track at a time';
|
||||
|
||||
@override
|
||||
String concurrentDownloadsCount(int count) {
|
||||
return 'Up to $count tracks at once';
|
||||
}
|
||||
|
||||
@override
|
||||
String get albumFolderArtistAlbum => 'Artiste / Album';
|
||||
|
||||
|
||||
@@ -1658,6 +1658,21 @@ class AppLocalizationsHi extends AppLocalizations {
|
||||
String get settingsDownloadNetworkSubtitle =>
|
||||
'Choose which network to use for downloads. When set to WiFi Only, downloads will pause on mobile data.';
|
||||
|
||||
@override
|
||||
String get settingsConcurrentDownloads => 'Concurrent downloads';
|
||||
|
||||
@override
|
||||
String get settingsConcurrentDownloadsSubtitle =>
|
||||
'Downloading several tracks at once is faster, but some providers may rate-limit parallel requests.';
|
||||
|
||||
@override
|
||||
String get concurrentDownloadsOne => '1 track at a time';
|
||||
|
||||
@override
|
||||
String concurrentDownloadsCount(int count) {
|
||||
return 'Up to $count tracks at once';
|
||||
}
|
||||
|
||||
@override
|
||||
String get albumFolderArtistAlbum => 'Artist / Album';
|
||||
|
||||
|
||||
@@ -1664,6 +1664,21 @@ class AppLocalizationsId extends AppLocalizations {
|
||||
String get settingsDownloadNetworkSubtitle =>
|
||||
'Pilih jaringan mana yang akan digunakan untuk mengunduh. Jika diatur ke Hanya WiFi, unduhan akan berhenti sementara dan menggunakan data seluler.';
|
||||
|
||||
@override
|
||||
String get settingsConcurrentDownloads => 'Concurrent downloads';
|
||||
|
||||
@override
|
||||
String get settingsConcurrentDownloadsSubtitle =>
|
||||
'Downloading several tracks at once is faster, but some providers may rate-limit parallel requests.';
|
||||
|
||||
@override
|
||||
String get concurrentDownloadsOne => '1 track at a time';
|
||||
|
||||
@override
|
||||
String concurrentDownloadsCount(int count) {
|
||||
return 'Up to $count tracks at once';
|
||||
}
|
||||
|
||||
@override
|
||||
String get albumFolderArtistAlbum => 'Artis / Album';
|
||||
|
||||
|
||||
@@ -1646,6 +1646,21 @@ class AppLocalizationsJa extends AppLocalizations {
|
||||
String get settingsDownloadNetworkSubtitle =>
|
||||
'Choose which network to use for downloads. When set to WiFi Only, downloads will pause on mobile data.';
|
||||
|
||||
@override
|
||||
String get settingsConcurrentDownloads => 'Concurrent downloads';
|
||||
|
||||
@override
|
||||
String get settingsConcurrentDownloadsSubtitle =>
|
||||
'Downloading several tracks at once is faster, but some providers may rate-limit parallel requests.';
|
||||
|
||||
@override
|
||||
String get concurrentDownloadsOne => '1 track at a time';
|
||||
|
||||
@override
|
||||
String concurrentDownloadsCount(int count) {
|
||||
return 'Up to $count tracks at once';
|
||||
}
|
||||
|
||||
@override
|
||||
String get albumFolderArtistAlbum => 'アーティスト / アルバム';
|
||||
|
||||
|
||||
@@ -1643,6 +1643,21 @@ class AppLocalizationsKo extends AppLocalizations {
|
||||
String get settingsDownloadNetworkSubtitle =>
|
||||
'Choose which network to use for downloads. When set to WiFi Only, downloads will pause on mobile data.';
|
||||
|
||||
@override
|
||||
String get settingsConcurrentDownloads => 'Concurrent downloads';
|
||||
|
||||
@override
|
||||
String get settingsConcurrentDownloadsSubtitle =>
|
||||
'Downloading several tracks at once is faster, but some providers may rate-limit parallel requests.';
|
||||
|
||||
@override
|
||||
String get concurrentDownloadsOne => '1 track at a time';
|
||||
|
||||
@override
|
||||
String concurrentDownloadsCount(int count) {
|
||||
return 'Up to $count tracks at once';
|
||||
}
|
||||
|
||||
@override
|
||||
String get albumFolderArtistAlbum => 'Artist / Album';
|
||||
|
||||
|
||||
@@ -1658,6 +1658,21 @@ class AppLocalizationsNl extends AppLocalizations {
|
||||
String get settingsDownloadNetworkSubtitle =>
|
||||
'Choose which network to use for downloads. When set to WiFi Only, downloads will pause on mobile data.';
|
||||
|
||||
@override
|
||||
String get settingsConcurrentDownloads => 'Concurrent downloads';
|
||||
|
||||
@override
|
||||
String get settingsConcurrentDownloadsSubtitle =>
|
||||
'Downloading several tracks at once is faster, but some providers may rate-limit parallel requests.';
|
||||
|
||||
@override
|
||||
String get concurrentDownloadsOne => '1 track at a time';
|
||||
|
||||
@override
|
||||
String concurrentDownloadsCount(int count) {
|
||||
return 'Up to $count tracks at once';
|
||||
}
|
||||
|
||||
@override
|
||||
String get albumFolderArtistAlbum => 'Artist / Album';
|
||||
|
||||
|
||||
@@ -1658,6 +1658,21 @@ class AppLocalizationsPt extends AppLocalizations {
|
||||
String get settingsDownloadNetworkSubtitle =>
|
||||
'Choose which network to use for downloads. When set to WiFi Only, downloads will pause on mobile data.';
|
||||
|
||||
@override
|
||||
String get settingsConcurrentDownloads => 'Concurrent downloads';
|
||||
|
||||
@override
|
||||
String get settingsConcurrentDownloadsSubtitle =>
|
||||
'Downloading several tracks at once is faster, but some providers may rate-limit parallel requests.';
|
||||
|
||||
@override
|
||||
String get concurrentDownloadsOne => '1 track at a time';
|
||||
|
||||
@override
|
||||
String concurrentDownloadsCount(int count) {
|
||||
return 'Up to $count tracks at once';
|
||||
}
|
||||
|
||||
@override
|
||||
String get albumFolderArtistAlbum => 'Artist / Album';
|
||||
|
||||
|
||||
@@ -1681,6 +1681,21 @@ class AppLocalizationsRu extends AppLocalizations {
|
||||
String get settingsDownloadNetworkSubtitle =>
|
||||
'Выберите, какую сеть использовать для скачивания. Когда установлено значение только WiFi — скачивания через мобильную сеть будут приостановлены.';
|
||||
|
||||
@override
|
||||
String get settingsConcurrentDownloads => 'Concurrent downloads';
|
||||
|
||||
@override
|
||||
String get settingsConcurrentDownloadsSubtitle =>
|
||||
'Downloading several tracks at once is faster, but some providers may rate-limit parallel requests.';
|
||||
|
||||
@override
|
||||
String get concurrentDownloadsOne => '1 track at a time';
|
||||
|
||||
@override
|
||||
String concurrentDownloadsCount(int count) {
|
||||
return 'Up to $count tracks at once';
|
||||
}
|
||||
|
||||
@override
|
||||
String get albumFolderArtistAlbum => 'Исполнитель / Альбом';
|
||||
|
||||
|
||||
@@ -1677,6 +1677,21 @@ class AppLocalizationsTr extends AppLocalizations {
|
||||
String get settingsDownloadNetworkSubtitle =>
|
||||
'İndirmeler için hangi ağın kullanılacağını seçin. Yalnızca WiFi olarak ayarlandığında, mobil veriye geçildiğinde indirmeler duraklatılır.';
|
||||
|
||||
@override
|
||||
String get settingsConcurrentDownloads => 'Concurrent downloads';
|
||||
|
||||
@override
|
||||
String get settingsConcurrentDownloadsSubtitle =>
|
||||
'Downloading several tracks at once is faster, but some providers may rate-limit parallel requests.';
|
||||
|
||||
@override
|
||||
String get concurrentDownloadsOne => '1 track at a time';
|
||||
|
||||
@override
|
||||
String concurrentDownloadsCount(int count) {
|
||||
return 'Up to $count tracks at once';
|
||||
}
|
||||
|
||||
@override
|
||||
String get albumFolderArtistAlbum => 'Sanatçı / Albüm';
|
||||
|
||||
|
||||
@@ -1684,6 +1684,21 @@ class AppLocalizationsUk extends AppLocalizations {
|
||||
String get settingsDownloadNetworkSubtitle =>
|
||||
'Вибрати мережу для завантажень. Якщо встановлено значення «Тільки Wi-Fi», завантаження призупиняться через мобільні дані.';
|
||||
|
||||
@override
|
||||
String get settingsConcurrentDownloads => 'Concurrent downloads';
|
||||
|
||||
@override
|
||||
String get settingsConcurrentDownloadsSubtitle =>
|
||||
'Downloading several tracks at once is faster, but some providers may rate-limit parallel requests.';
|
||||
|
||||
@override
|
||||
String get concurrentDownloadsOne => '1 track at a time';
|
||||
|
||||
@override
|
||||
String concurrentDownloadsCount(int count) {
|
||||
return 'Up to $count tracks at once';
|
||||
}
|
||||
|
||||
@override
|
||||
String get albumFolderArtistAlbum => 'Артист / Альбом';
|
||||
|
||||
|
||||
@@ -1658,6 +1658,21 @@ class AppLocalizationsZh extends AppLocalizations {
|
||||
String get settingsDownloadNetworkSubtitle =>
|
||||
'Choose which network to use for downloads. When set to WiFi Only, downloads will pause on mobile data.';
|
||||
|
||||
@override
|
||||
String get settingsConcurrentDownloads => 'Concurrent downloads';
|
||||
|
||||
@override
|
||||
String get settingsConcurrentDownloadsSubtitle =>
|
||||
'Downloading several tracks at once is faster, but some providers may rate-limit parallel requests.';
|
||||
|
||||
@override
|
||||
String get concurrentDownloadsOne => '1 track at a time';
|
||||
|
||||
@override
|
||||
String concurrentDownloadsCount(int count) {
|
||||
return 'Up to $count tracks at once';
|
||||
}
|
||||
|
||||
@override
|
||||
String get albumFolderArtistAlbum => 'Artist / Album';
|
||||
|
||||
|
||||
@@ -2175,6 +2175,27 @@
|
||||
"@settingsDownloadNetworkSubtitle": {
|
||||
"description": "Subtitle explaining network preference"
|
||||
},
|
||||
"settingsConcurrentDownloads": "Concurrent downloads",
|
||||
"@settingsConcurrentDownloads": {
|
||||
"description": "Setting title - how many tracks download at the same time"
|
||||
},
|
||||
"settingsConcurrentDownloadsSubtitle": "Downloading several tracks at once is faster, but some providers may rate-limit parallel requests.",
|
||||
"@settingsConcurrentDownloadsSubtitle": {
|
||||
"description": "Subtitle explaining the concurrent downloads picker"
|
||||
},
|
||||
"concurrentDownloadsOne": "1 track at a time",
|
||||
"@concurrentDownloadsOne": {
|
||||
"description": "Concurrent downloads option - sequential"
|
||||
},
|
||||
"concurrentDownloadsCount": "Up to {count} tracks at once",
|
||||
"@concurrentDownloadsCount": {
|
||||
"description": "Concurrent downloads option - parallel",
|
||||
"placeholders": {
|
||||
"count": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"albumFolderArtistAlbum": "Artist / Album",
|
||||
"@albumFolderArtistAlbum": {
|
||||
"description": "Album folder option"
|
||||
|
||||
@@ -62,6 +62,8 @@ class AppSettings {
|
||||
songLinkRegion; // SongLink userCountry region code used for platform lookup
|
||||
final bool
|
||||
nativeDownloadWorkerEnabled; // Experimental Android service-owned worker
|
||||
final int
|
||||
concurrentDownloads; // Max simultaneous downloads in the Dart queue (1-3)
|
||||
|
||||
final bool localLibraryEnabled;
|
||||
final String localLibraryPath;
|
||||
@@ -140,6 +142,7 @@ class AppSettings {
|
||||
this.allowLocalNetwork = false,
|
||||
this.songLinkRegion = 'US',
|
||||
this.nativeDownloadWorkerEnabled = false,
|
||||
this.concurrentDownloads = 1,
|
||||
this.localLibraryEnabled = false,
|
||||
this.localLibraryPath = '',
|
||||
this.localLibraryBookmark = '',
|
||||
@@ -208,6 +211,7 @@ class AppSettings {
|
||||
bool? allowLocalNetwork,
|
||||
String? songLinkRegion,
|
||||
bool? nativeDownloadWorkerEnabled,
|
||||
int? concurrentDownloads,
|
||||
bool? localLibraryEnabled,
|
||||
String? localLibraryPath,
|
||||
String? localLibraryBookmark,
|
||||
@@ -289,6 +293,7 @@ class AppSettings {
|
||||
songLinkRegion: songLinkRegion ?? this.songLinkRegion,
|
||||
nativeDownloadWorkerEnabled:
|
||||
nativeDownloadWorkerEnabled ?? this.nativeDownloadWorkerEnabled,
|
||||
concurrentDownloads: concurrentDownloads ?? this.concurrentDownloads,
|
||||
localLibraryEnabled: localLibraryEnabled ?? this.localLibraryEnabled,
|
||||
localLibraryPath: localLibraryPath ?? this.localLibraryPath,
|
||||
localLibraryBookmark: localLibraryBookmark ?? this.localLibraryBookmark,
|
||||
|
||||
@@ -62,6 +62,7 @@ AppSettings _$AppSettingsFromJson(Map<String, dynamic> json) => AppSettings(
|
||||
songLinkRegion: json['songLinkRegion'] as String? ?? 'US',
|
||||
nativeDownloadWorkerEnabled:
|
||||
json['nativeDownloadWorkerEnabled'] as bool? ?? false,
|
||||
concurrentDownloads: (json['concurrentDownloads'] as num?)?.toInt() ?? 1,
|
||||
localLibraryEnabled: json['localLibraryEnabled'] as bool? ?? false,
|
||||
localLibraryPath: json['localLibraryPath'] as String? ?? '',
|
||||
localLibraryBookmark: json['localLibraryBookmark'] as String? ?? '',
|
||||
@@ -138,6 +139,7 @@ Map<String, dynamic> _$AppSettingsToJson(
|
||||
'allowLocalNetwork': instance.allowLocalNetwork,
|
||||
'songLinkRegion': instance.songLinkRegion,
|
||||
'nativeDownloadWorkerEnabled': instance.nativeDownloadWorkerEnabled,
|
||||
'concurrentDownloads': instance.concurrentDownloads,
|
||||
'localLibraryEnabled': instance.localLibraryEnabled,
|
||||
'localLibraryPath': instance.localLibraryPath,
|
||||
'localLibraryBookmark': instance.localLibraryBookmark,
|
||||
|
||||
@@ -3742,6 +3742,12 @@ class DownloadQueueNotifier extends Notifier<DownloadQueueState> {
|
||||
if (!Platform.isAndroid || !settings.nativeDownloadWorkerEnabled) {
|
||||
return false;
|
||||
}
|
||||
if (settings.concurrentDownloads > 1) {
|
||||
// The experimental native worker downloads strictly sequentially, so
|
||||
// prefer the Dart queue when the user enabled concurrent downloads.
|
||||
_log.i('Concurrent downloads enabled; skipping native worker');
|
||||
return false;
|
||||
}
|
||||
if (!settings.useExtensionProviders) {
|
||||
return false;
|
||||
}
|
||||
@@ -5470,7 +5476,7 @@ class DownloadQueueNotifier extends Notifier<DownloadQueueState> {
|
||||
}
|
||||
|
||||
try {
|
||||
await _processQueueSequential();
|
||||
await _runQueueLoop();
|
||||
} finally {
|
||||
if (iosDownloadBookmarkActive) {
|
||||
await PlatformBridge.stopAccessingIosBookmark();
|
||||
@@ -5550,7 +5556,7 @@ class DownloadQueueNotifier extends Notifier<DownloadQueueState> {
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _processQueueSequential() async {
|
||||
Future<void> _runQueueLoop() async {
|
||||
final activeDownloads = <String, Future<void>>{};
|
||||
|
||||
_startMultiProgressPolling();
|
||||
@@ -5582,9 +5588,11 @@ class DownloadQueueNotifier extends Notifier<DownloadQueueState> {
|
||||
break;
|
||||
}
|
||||
|
||||
// One download at a time: only start the next item once the current
|
||||
// download has finished, to stay within the API's single-request limit.
|
||||
if (activeDownloads.isEmpty &&
|
||||
final maxConcurrent = ref
|
||||
.read(settingsProvider)
|
||||
.concurrentDownloads
|
||||
.clamp(1, 3);
|
||||
while (activeDownloads.length < maxConcurrent &&
|
||||
queuedItems.isNotEmpty &&
|
||||
!state.isPaused) {
|
||||
final item = queuedItems.removeAt(0);
|
||||
|
||||
@@ -613,6 +613,11 @@ class SettingsNotifier extends Notifier<AppSettings> {
|
||||
_saveSettings();
|
||||
}
|
||||
|
||||
void setConcurrentDownloads(int count) {
|
||||
state = state.copyWith(concurrentDownloads: count.clamp(1, 3));
|
||||
_saveSettings();
|
||||
}
|
||||
|
||||
void setNetworkCompatibilityMode(bool enabled) {
|
||||
state = state.copyWith(networkCompatibilityMode: enabled);
|
||||
_saveSettings();
|
||||
|
||||
@@ -195,6 +195,20 @@ class _DownloadSettingsPageState extends ConsumerState<DownloadSettingsPage> {
|
||||
settings.downloadNetworkMode,
|
||||
),
|
||||
),
|
||||
SettingsItem(
|
||||
icon: Icons.dynamic_feed_outlined,
|
||||
title: context.l10n.settingsConcurrentDownloads,
|
||||
subtitle: settings.concurrentDownloads <= 1
|
||||
? context.l10n.concurrentDownloadsOne
|
||||
: context.l10n.concurrentDownloadsCount(
|
||||
settings.concurrentDownloads,
|
||||
),
|
||||
onTap: () => _showConcurrentDownloadsPicker(
|
||||
context,
|
||||
ref,
|
||||
settings.concurrentDownloads,
|
||||
),
|
||||
),
|
||||
if (Platform.isAndroid)
|
||||
SettingsSwitchItem(
|
||||
icon: Icons.downloading_outlined,
|
||||
@@ -598,6 +612,73 @@ class _DownloadSettingsPageState extends ConsumerState<DownloadSettingsPage> {
|
||||
);
|
||||
}
|
||||
|
||||
void _showConcurrentDownloadsPicker(
|
||||
BuildContext context,
|
||||
WidgetRef ref,
|
||||
int current,
|
||||
) {
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
showModalBottomSheet<void>(
|
||||
context: context,
|
||||
useRootNavigator: true,
|
||||
backgroundColor: colorScheme.surfaceContainerHigh,
|
||||
shape: const RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.vertical(top: Radius.circular(28)),
|
||||
),
|
||||
builder: (context) => SafeArea(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(24, 24, 24, 8),
|
||||
child: Text(
|
||||
context.l10n.settingsConcurrentDownloads,
|
||||
style: Theme.of(
|
||||
context,
|
||||
).textTheme.titleLarge?.copyWith(fontWeight: FontWeight.bold),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(24, 0, 24, 16),
|
||||
child: Text(
|
||||
context.l10n.settingsConcurrentDownloadsSubtitle,
|
||||
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
||||
color: colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
),
|
||||
for (final count in const [1, 2, 3])
|
||||
ListTile(
|
||||
leading: Icon(
|
||||
count == 1
|
||||
? Icons.looks_one_outlined
|
||||
: count == 2
|
||||
? Icons.looks_two_outlined
|
||||
: Icons.looks_3_outlined,
|
||||
),
|
||||
title: Text(
|
||||
count == 1
|
||||
? context.l10n.concurrentDownloadsOne
|
||||
: context.l10n.concurrentDownloadsCount(count),
|
||||
),
|
||||
trailing: current == count
|
||||
? Icon(Icons.check, color: colorScheme.primary)
|
||||
: null,
|
||||
onTap: () {
|
||||
ref
|
||||
.read(settingsProvider.notifier)
|
||||
.setConcurrentDownloads(count);
|
||||
Navigator.pop(context);
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _showSongLinkRegionPicker(
|
||||
BuildContext context,
|
||||
WidgetRef ref,
|
||||
|
||||
Reference in New Issue
Block a user