From b0f5dd89515a9232e442db6ffb27cafe59432dd8 Mon Sep 17 00:00:00 2001 From: rang <378694192@qq.com> Date: Mon, 29 Dec 2025 17:56:03 +0800 Subject: [PATCH] 123 --- ios/Runner/Info.plist | 5 + .../downloads/core/download_manager.dart | 15 +- .../downloads/providers/download_manager.dart | 23 ++ .../providers/download_manager.g.dart | 4 +- .../view/library_item_actions.dart | 22 +- .../player/providers/abs_provider.g.dart | 2 +- .../player/view/player_expanded_desktop.dart | 4 +- .../widgets/chapter_selection_button.dart | 9 +- .../settings/models/app_settings.dart | 1 + .../settings/models/app_settings.freezed.dart | 44 +++- .../settings/models/app_settings.g.dart | 2 + .../settings/view/app_settings_page.dart | 10 +- .../settings/view/download_settings_page.dart | 239 ++++++++++++++++++ lib/router/constants.dart | 5 + lib/router/router.dart | 7 + macos/Flutter/GeneratedPluginRegistrant.swift | 2 + pubspec.lock | 109 +++++--- pubspec.yaml | 2 +- 18 files changed, 441 insertions(+), 64 deletions(-) create mode 100644 lib/features/settings/view/download_settings_page.dart diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index 5648041..086d554 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -54,5 +54,10 @@ UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight + + LSSupportsOpeningDocumentsInPlace + + UIFileSharingEnabled + diff --git a/lib/features/downloads/core/download_manager.dart b/lib/features/downloads/core/download_manager.dart index 678e6cd..19738bf 100644 --- a/lib/features/downloads/core/download_manager.dart +++ b/lib/features/downloads/core/download_manager.dart @@ -22,6 +22,7 @@ class AudiobookDownloadManager { this.requiresWiFi = true, this.retries = 0, this.allowPause = false, + this.path = '', // /// The maximum number of concurrent tasks to run at any given time. // int maxConcurrent = 3, @@ -60,6 +61,9 @@ class AudiobookDownloadManager { // whether to allow pausing of downloads final bool allowPause; + // 下载目录 + final String path; + final StreamController _taskStatusController = StreamController.broadcast(); @@ -68,11 +72,16 @@ class AudiobookDownloadManager { late StreamSubscription _updatesSubscription; Future queueAudioBookDownload( - LibraryItemExpanded item, - ) async { + LibraryItemExpanded item, { + String prePath = '', + }) async { _logger.info('queuing download for item: ${item.id}'); // create a download task for each file in the item for (final file in item.libraryFiles) { + // 仅下载音频和视频 + if (![FileType.audio, FileType.video].contains(file.fileType)) { + continue; + } // check if the file is already downloaded if (isFileDownloaded( constructFilePath(item, file), @@ -84,7 +93,7 @@ class AudiobookDownloadManager { final task = DownloadTask( taskId: file.ino, url: file.url(baseUrl, item.id, token).toString(), - directory: item.relPath, + directory: prePath + item.relPath, filename: file.metadata.filename, requiresWiFi: requiresWiFi, retries: retries, diff --git a/lib/features/downloads/providers/download_manager.dart b/lib/features/downloads/providers/download_manager.dart index 8b7c203..bdbe15e 100644 --- a/lib/features/downloads/providers/download_manager.dart +++ b/lib/features/downloads/providers/download_manager.dart @@ -1,3 +1,5 @@ +import 'dart:io'; + import 'package:background_downloader/background_downloader.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:logging/logging.dart'; @@ -26,6 +28,7 @@ class SimpleDownloadManager extends _$SimpleDownloadManager { requiresWiFi: downloadSettings.requiresWiFi, retries: downloadSettings.retries, allowPause: downloadSettings.allowPause, + path: downloadSettings.path, ); core.tq.maxConcurrent = downloadSettings.maxConcurrent; core.tq.maxConcurrentByHost = downloadSettings.maxConcurrentByHost; @@ -56,6 +59,8 @@ class DownloadManager extends _$DownloadManager { LibraryItemExpanded item, ) async { _logger.fine('queueing download for ${item.id}'); + // final appSettings = ref.read(appSettingsProvider); + await state.queueAudioBookDownload( item, ); @@ -66,6 +71,24 @@ class DownloadManager extends _$DownloadManager { await state.deleteDownloadedItem(item); ref.notifyListeners(); } + + String _getDirectory(String path) { + if (Platform.isWindows) { + return path; + } + return path; + } + + BaseDirectory _getBaseDirectory() { + if (Platform.isIOS) { + return BaseDirectory.applicationDocuments; + } else if (Platform.isAndroid) { + return BaseDirectory.temporary; + } else if (Platform.isWindows) { + return BaseDirectory.root; + } + return BaseDirectory.applicationSupport; + } } @riverpod diff --git a/lib/features/downloads/providers/download_manager.g.dart b/lib/features/downloads/providers/download_manager.g.dart index 6b08886..0df3141 100644 --- a/lib/features/downloads/providers/download_manager.g.dart +++ b/lib/features/downloads/providers/download_manager.g.dart @@ -160,7 +160,7 @@ class _DownloadHistoryProviderElement } String _$simpleDownloadManagerHash() => - r'8ab13f06ec5f2f73b73064bd285813dc890b7f36'; + r'da5798e4becce751db80c41b93a48217418e4648'; /// See also [SimpleDownloadManager]. @ProviderFor(SimpleDownloadManager) @@ -176,7 +176,7 @@ final simpleDownloadManagerProvider = NotifierProvider; -String _$downloadManagerHash() => r'852012e32e613f86445afc7f7e4e85bec808e982'; +String _$downloadManagerHash() => r'92afe484d6735d5de53473011ea9ecbad107fc1c'; /// See also [DownloadManager]. @ProviderFor(DownloadManager) diff --git a/lib/features/item_viewer/view/library_item_actions.dart b/lib/features/item_viewer/view/library_item_actions.dart index 99d25fd..230eb13 100644 --- a/lib/features/item_viewer/view/library_item_actions.dart +++ b/lib/features/item_viewer/view/library_item_actions.dart @@ -94,7 +94,7 @@ class LibraryItemActions extends HookConsumerWidget { }, icon: const Icon(Icons.share_rounded), ), - LibItemDownButton(item.id), + LibItemDownButton(item: item), // download button LibItemDownloadButton(item: item), @@ -205,8 +205,8 @@ class LibraryItemActions extends HookConsumerWidget { } class LibItemDownButton extends HookConsumerWidget { - const LibItemDownButton(this.libraryItemId, {super.key}); - final String libraryItemId; + const LibItemDownButton({required this.item, super.key}); + final shelfsdk.LibraryItemExpanded item; @override Widget build(BuildContext context, WidgetRef ref) { return IconButton( @@ -217,7 +217,7 @@ class LibItemDownButton extends HookConsumerWidget { builder: (context) { return FractionallySizedBox( heightFactor: 0.8, - child: LibItemDownSheet(libraryItemId), + child: LibItemDownSheet(item.id), ); }, ); @@ -253,13 +253,17 @@ class LibItemDownSheet extends HookConsumerWidget { mainAxisAlignment: MainAxisAlignment.end, children: [ IconButton( - onPressed: () {}, + onPressed: () { + appLogger.fine('Pressed delete download button'); + ref + .read(downloadManagerProvider.notifier) + .deleteDownloadedItem( + item, + ); + }, icon: Icon(Icons.delete_outlined), ), - IconButton( - onPressed: () {}, - icon: Icon(Icons.download_outlined), - ), + LibItemDownloadButton(item: item), ], ), ), diff --git a/lib/features/player/providers/abs_provider.g.dart b/lib/features/player/providers/abs_provider.g.dart index 005e46a..3bf89d6 100644 --- a/lib/features/player/providers/abs_provider.g.dart +++ b/lib/features/player/providers/abs_provider.g.dart @@ -275,7 +275,7 @@ final playerStateProvider = ); typedef _$PlayerState = AutoDisposeNotifier; -String _$currentBookHash() => r'b4f6b6ccc772631db3dfd9070be3d7487333544d'; +String _$currentBookHash() => r'790af1f9502b12879fc22c900ed5e3572381ab1e'; /// See also [CurrentBook]. @ProviderFor(CurrentBook) diff --git a/lib/features/player/view/player_expanded_desktop.dart b/lib/features/player/view/player_expanded_desktop.dart index 7e2365f..597dbc8 100644 --- a/lib/features/player/view/player_expanded_desktop.dart +++ b/lib/features/player/view/player_expanded_desktop.dart @@ -101,7 +101,9 @@ class PlayerExpandedDesktop extends HookConsumerWidget { ), ), ), - child: ChapterSelectionModal(), + child: ChapterSelectionModal( + back: false, + ), ), ), ], diff --git a/lib/features/player/view/widgets/chapter_selection_button.dart b/lib/features/player/view/widgets/chapter_selection_button.dart index d67d1ec..4ff7888 100644 --- a/lib/features/player/view/widgets/chapter_selection_button.dart +++ b/lib/features/player/view/widgets/chapter_selection_button.dart @@ -49,7 +49,9 @@ class ChapterSelectionButton extends HookConsumerWidget { class ChapterSelectionModal extends HookConsumerWidget { const ChapterSelectionModal({ super.key, + this.back = true, }); + final bool back; @override Widget build(BuildContext context, WidgetRef ref) { @@ -108,8 +110,11 @@ class ChapterSelectionModal extends HookConsumerWidget { : const Icon(Icons.play_arrow), selected: isCurrent, onTap: () { - Navigator.of(context).pop(); - ref.read(absPlayerProvider).switchChapter(chapter.id); + if (back) { + Navigator.of(context).pop(); + } else { + ref.read(absPlayerProvider).switchChapter(chapter.id); + } }, ); }, diff --git a/lib/features/settings/models/app_settings.dart b/lib/features/settings/models/app_settings.dart index 744ebf7..04c10e3 100644 --- a/lib/features/settings/models/app_settings.dart +++ b/lib/features/settings/models/app_settings.dart @@ -143,6 +143,7 @@ class DownloadSettings with _$DownloadSettings { @Default(3) int maxConcurrent, @Default(3) int maxConcurrentByHost, @Default(3) int maxConcurrentByGroup, + @Default('') String path, }) = _DownloadSettings; factory DownloadSettings.fromJson(Map json) => diff --git a/lib/features/settings/models/app_settings.freezed.dart b/lib/features/settings/models/app_settings.freezed.dart index d0363e7..f84e13a 100644 --- a/lib/features/settings/models/app_settings.freezed.dart +++ b/lib/features/settings/models/app_settings.freezed.dart @@ -1970,6 +1970,7 @@ mixin _$DownloadSettings { int get maxConcurrent => throw _privateConstructorUsedError; int get maxConcurrentByHost => throw _privateConstructorUsedError; int get maxConcurrentByGroup => throw _privateConstructorUsedError; + String get path => throw _privateConstructorUsedError; /// Serializes this DownloadSettings to a JSON map. Map toJson() => throw _privateConstructorUsedError; @@ -1993,7 +1994,8 @@ abstract class $DownloadSettingsCopyWith<$Res> { bool allowPause, int maxConcurrent, int maxConcurrentByHost, - int maxConcurrentByGroup}); + int maxConcurrentByGroup, + String path}); } /// @nodoc @@ -2017,6 +2019,7 @@ class _$DownloadSettingsCopyWithImpl<$Res, $Val extends DownloadSettings> Object? maxConcurrent = null, Object? maxConcurrentByHost = null, Object? maxConcurrentByGroup = null, + Object? path = null, }) { return _then(_value.copyWith( requiresWiFi: null == requiresWiFi @@ -2043,6 +2046,10 @@ class _$DownloadSettingsCopyWithImpl<$Res, $Val extends DownloadSettings> ? _value.maxConcurrentByGroup : maxConcurrentByGroup // ignore: cast_nullable_to_non_nullable as int, + path: null == path + ? _value.path + : path // ignore: cast_nullable_to_non_nullable + as String, ) as $Val); } } @@ -2061,7 +2068,8 @@ abstract class _$$DownloadSettingsImplCopyWith<$Res> bool allowPause, int maxConcurrent, int maxConcurrentByHost, - int maxConcurrentByGroup}); + int maxConcurrentByGroup, + String path}); } /// @nodoc @@ -2083,6 +2091,7 @@ class __$$DownloadSettingsImplCopyWithImpl<$Res> Object? maxConcurrent = null, Object? maxConcurrentByHost = null, Object? maxConcurrentByGroup = null, + Object? path = null, }) { return _then(_$DownloadSettingsImpl( requiresWiFi: null == requiresWiFi @@ -2109,6 +2118,10 @@ class __$$DownloadSettingsImplCopyWithImpl<$Res> ? _value.maxConcurrentByGroup : maxConcurrentByGroup // ignore: cast_nullable_to_non_nullable as int, + path: null == path + ? _value.path + : path // ignore: cast_nullable_to_non_nullable + as String, )); } } @@ -2122,7 +2135,8 @@ class _$DownloadSettingsImpl implements _DownloadSettings { this.allowPause = true, this.maxConcurrent = 3, this.maxConcurrentByHost = 3, - this.maxConcurrentByGroup = 3}); + this.maxConcurrentByGroup = 3, + this.path = ''}); factory _$DownloadSettingsImpl.fromJson(Map json) => _$$DownloadSettingsImplFromJson(json); @@ -2145,10 +2159,13 @@ class _$DownloadSettingsImpl implements _DownloadSettings { @override @JsonKey() final int maxConcurrentByGroup; + @override + @JsonKey() + final String path; @override String toString() { - return 'DownloadSettings(requiresWiFi: $requiresWiFi, retries: $retries, allowPause: $allowPause, maxConcurrent: $maxConcurrent, maxConcurrentByHost: $maxConcurrentByHost, maxConcurrentByGroup: $maxConcurrentByGroup)'; + return 'DownloadSettings(requiresWiFi: $requiresWiFi, retries: $retries, allowPause: $allowPause, maxConcurrent: $maxConcurrent, maxConcurrentByHost: $maxConcurrentByHost, maxConcurrentByGroup: $maxConcurrentByGroup, path: $path)'; } @override @@ -2166,13 +2183,21 @@ class _$DownloadSettingsImpl implements _DownloadSettings { (identical(other.maxConcurrentByHost, maxConcurrentByHost) || other.maxConcurrentByHost == maxConcurrentByHost) && (identical(other.maxConcurrentByGroup, maxConcurrentByGroup) || - other.maxConcurrentByGroup == maxConcurrentByGroup)); + other.maxConcurrentByGroup == maxConcurrentByGroup) && + (identical(other.path, path) || other.path == path)); } @JsonKey(includeFromJson: false, includeToJson: false) @override - int get hashCode => Object.hash(runtimeType, requiresWiFi, retries, - allowPause, maxConcurrent, maxConcurrentByHost, maxConcurrentByGroup); + int get hashCode => Object.hash( + runtimeType, + requiresWiFi, + retries, + allowPause, + maxConcurrent, + maxConcurrentByHost, + maxConcurrentByGroup, + path); /// Create a copy of DownloadSettings /// with the given fields replaced by the non-null parameter values. @@ -2198,7 +2223,8 @@ abstract class _DownloadSettings implements DownloadSettings { final bool allowPause, final int maxConcurrent, final int maxConcurrentByHost, - final int maxConcurrentByGroup}) = _$DownloadSettingsImpl; + final int maxConcurrentByGroup, + final String path}) = _$DownloadSettingsImpl; factory _DownloadSettings.fromJson(Map json) = _$DownloadSettingsImpl.fromJson; @@ -2215,6 +2241,8 @@ abstract class _DownloadSettings implements DownloadSettings { int get maxConcurrentByHost; @override int get maxConcurrentByGroup; + @override + String get path; /// Create a copy of DownloadSettings /// with the given fields replaced by the non-null parameter values. diff --git a/lib/features/settings/models/app_settings.g.dart b/lib/features/settings/models/app_settings.g.dart index 2f7e09f..a868347 100644 --- a/lib/features/settings/models/app_settings.g.dart +++ b/lib/features/settings/models/app_settings.g.dart @@ -239,6 +239,7 @@ _$DownloadSettingsImpl _$$DownloadSettingsImplFromJson( maxConcurrentByHost: (json['maxConcurrentByHost'] as num?)?.toInt() ?? 3, maxConcurrentByGroup: (json['maxConcurrentByGroup'] as num?)?.toInt() ?? 3, + path: json['path'] as String? ?? '', ); Map _$$DownloadSettingsImplToJson( @@ -250,6 +251,7 @@ Map _$$DownloadSettingsImplToJson( 'maxConcurrent': instance.maxConcurrent, 'maxConcurrentByHost': instance.maxConcurrentByHost, 'maxConcurrentByGroup': instance.maxConcurrentByGroup, + 'path': instance.path, }; _$NotificationSettingsImpl _$$NotificationSettingsImplFromJson( diff --git a/lib/features/settings/view/app_settings_page.dart b/lib/features/settings/view/app_settings_page.dart index 844d3e7..64e5efd 100644 --- a/lib/features/settings/view/app_settings_page.dart +++ b/lib/features/settings/view/app_settings_page.dart @@ -39,7 +39,7 @@ class AppSettingsPage extends HookConsumerWidget { tiles: [ SettingsTile( title: Text(S.of(context).language), - leading: const Icon(Icons.play_arrow), + leading: const Icon(Icons.language), trailing: DropdownButton( value: appSettings.language, items: S.delegate.supportedLocales.map((locale) { @@ -66,6 +66,14 @@ class AppSettingsPage extends HookConsumerWidget { context.pushNamed(Routes.playerSettings.name); }, ), + SettingsTile( + title: Text('下载设置'), + leading: const Icon(Icons.download), + description: Text('自定义下载设置'), + onPressed: (context) { + context.pushNamed(Routes.downloadSettings.name); + }, + ), NavigationWithSwitchTile( title: Text(S.of(context).autoTurnOnSleepTimer), description: Text(S.of(context).automaticallyDescription), diff --git a/lib/features/settings/view/download_settings_page.dart b/lib/features/settings/view/download_settings_page.dart new file mode 100644 index 0000000..dad5c05 --- /dev/null +++ b/lib/features/settings/view/download_settings_page.dart @@ -0,0 +1,239 @@ +import 'dart:io'; + +import 'package:duration_picker/duration_picker.dart'; +import 'package:file_picker/file_picker.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:flutter_settings_ui/flutter_settings_ui.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:vaani/generated/l10n.dart'; +import 'package:vaani/features/settings/app_settings_provider.dart'; +import 'package:vaani/features/settings/view/buttons.dart'; +import 'package:vaani/features/settings/view/simple_settings_page.dart'; +import 'package:vaani/globals.dart'; +import 'package:vaani/shared/extensions/duration_format.dart'; + +class DownloadSettingsPage extends HookConsumerWidget { + const DownloadSettingsPage({ + super.key, + }); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final appSettings = ref.watch(appSettingsProvider); + final downloadSettings = appSettings.downloadSettings; + final primaryColor = Theme.of(context).colorScheme.primary; + + return SimpleSettingsPage( + title: Text(S.of(context).playerSettings), + sections: [ + SettingsSection( + margin: const EdgeInsetsDirectional.symmetric( + horizontal: 16.0, + vertical: 8.0, + ), + tiles: [ + // preferred settings for every book + if (Platform.isWindows) + SettingsTile( + title: Text('下载目录'), + leading: const Icon(Icons.folder_open_rounded), + description: Text( + '自定义下载目录', + ), + trailing: Text(downloadSettings.path), + onPressed: (context) async { + String? selectedDirectory = + await FilePicker.platform.getDirectoryPath(); + appLogger.info(selectedDirectory); + if (selectedDirectory != null) { + ref.read(appSettingsProvider.notifier).update( + appSettings.copyWith.downloadSettings( + path: selectedDirectory, + ), + ); + } + }, + ), + SettingsTile( + title: Text('并发数'), + leading: const Icon(Icons.folder_open_rounded), + description: Text('下载任务并发数'), + trailing: Text('${downloadSettings.maxConcurrent}'), + onPressed: (context) async {}, + ), + SettingsTile( + title: Text('Host并发数'), + leading: const Icon(Icons.folder_open_rounded), + description: Text('同一Host并发连接数'), + trailing: Text('${downloadSettings.maxConcurrentByHost}'), + onPressed: (context) async {}, + ), + SettingsTile( + title: Text('分组并发数'), + leading: const Icon(Icons.folder_open_rounded), + description: Text('同一分组并发数'), + trailing: Text('${downloadSettings.maxConcurrentByGroup}'), + onPressed: (context) async {}, + ), + ], + ), + ], + ); + } +} + +class TimeDurationSelector extends HookConsumerWidget { + const TimeDurationSelector({ + super.key, + this.title = const Text('Select Duration'), + this.baseUnit = BaseUnit.second, + this.initialValue = Duration.zero, + }); + + final Widget title; + final BaseUnit baseUnit; + final Duration initialValue; + + @override + Widget build(BuildContext context, WidgetRef ref) { + final duration = useState(initialValue); + return AlertDialog( + title: title, + content: DurationPicker( + duration: duration.value, + baseUnit: baseUnit, + onChange: (value) { + duration.value = value; + }, + ), + actions: [ + const CancelButton(), + OkButton( + onPressed: () { + Navigator.of(context).pop(duration.value); + }, + ), + ], + ); + } +} + +class SpeedPicker extends HookConsumerWidget { + const SpeedPicker({ + super.key, + this.initialValue = 1, + }); + + final double initialValue; + + @override + Widget build(BuildContext context, WidgetRef ref) { + final speedController = + useTextEditingController(text: initialValue.toString()); + final speed = useState(initialValue); + return AlertDialog( + title: Text(S.of(context).playerSettingsSpeedSelect), + content: TextField( + controller: speedController, + onChanged: (value) => speed.value = double.tryParse(value), + onSubmitted: (value) { + Navigator.of(context).pop(speed.value); + }, + autofocus: true, + keyboardType: TextInputType.number, + decoration: InputDecoration( + labelText: S.of(context).playerSettingsSpeed, + helper: Text(S.of(context).playerSettingsSpeedSelectHelper), + ), + ), + actions: [ + const CancelButton(), + OkButton( + onPressed: () { + Navigator.of(context).pop(speed.value); + }, + ), + ], + ); + } +} + +class SpeedOptionsPicker extends HookConsumerWidget { + const SpeedOptionsPicker({ + super.key, + this.initialValue = const [0.75, 1, 1.25, 1.5, 1.75, 2], + }); + + final List initialValue; + + @override + Widget build(BuildContext context, WidgetRef ref) { + final speedOptionAddController = useTextEditingController(); + final speedOptions = useState>(initialValue); + final focusNode = useFocusNode(); + return AlertDialog( + title: Text(S.of(context).playerSettingsSpeedOptionsSelect), + content: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Wrap( + spacing: 8.0, + runSpacing: 8.0, + children: speedOptions.value + .map( + (speed) => Chip( + label: Text('${speed}x'), + onDeleted: speed == 1 + ? null + : () { + speedOptions.value = + speedOptions.value.where((element) { + // speed option 1 can't be removed + return element != speed; + }).toList(); + }, + ), + ) + .toList() + ..sort((a, b) { + // if (a.label == const Text('1x')) { + // return -1; + // } else if (b.label == const Text('1x')) { + // return 1; + // } + return a.label.toString().compareTo(b.label.toString()); + }), + ), + TextField( + focusNode: focusNode, + autofocus: true, + controller: speedOptionAddController, + onSubmitted: (value) { + final newSpeed = double.tryParse(value); + if (newSpeed != null && !speedOptions.value.contains(newSpeed)) { + speedOptions.value = [...speedOptions.value, newSpeed]; + } + speedOptionAddController.clear(); + focusNode.requestFocus(); + }, + keyboardType: TextInputType.number, + decoration: InputDecoration( + labelText: S.of(context).playerSettingsSpeedOptionsSelectAdd, + helper: + Text(S.of(context).playerSettingsSpeedOptionsSelectAddHelper), + ), + ), + ], + ), + actions: [ + const CancelButton(), + OkButton( + onPressed: () { + Navigator.of(context).pop(speedOptions.value); + }, + ), + ], + ); + } +} diff --git a/lib/router/constants.dart b/lib/router/constants.dart index 3e25577..0891987 100644 --- a/lib/router/constants.dart +++ b/lib/router/constants.dart @@ -47,6 +47,11 @@ class Routes { name: 'playerSettings', parentRoute: settings, ); + static const downloadSettings = _SimpleRoute( + pathName: 'downloadSettings', + name: 'downloadSettings', + parentRoute: settings, + ); static const shakeDetectorSettings = _SimpleRoute( pathName: 'shakeDetector', name: 'shakeDetectorSettings', diff --git a/lib/router/router.dart b/lib/router/router.dart index 8fc0fc2..a49f246 100644 --- a/lib/router/router.dart +++ b/lib/router/router.dart @@ -9,6 +9,7 @@ import 'package:vaani/features/onboarding/view/callback_page.dart'; import 'package:vaani/features/onboarding/view/onboarding_single_page.dart'; import 'package:vaani/features/settings/view/app_settings_page.dart'; import 'package:vaani/features/settings/view/auto_sleep_timer_settings_page.dart'; +import 'package:vaani/features/settings/view/download_settings_page.dart'; import 'package:vaani/features/settings/view/home_page_settings_page.dart'; import 'package:vaani/features/settings/view/notification_settings_page.dart'; import 'package:vaani/features/settings/view/player_settings_page.dart'; @@ -213,6 +214,12 @@ class MyAppRouter { pageBuilder: defaultPageBuilder(const PlayerSettingsPage()), ), + GoRoute( + path: Routes.downloadSettings.pathName, + name: Routes.downloadSettings.name, + pageBuilder: + defaultPageBuilder(const DownloadSettingsPage()), + ), GoRoute( path: Routes.shakeDetectorSettings.pathName, name: Routes.shakeDetectorSettings.name, diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index e7aa69f..c6b463e 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -9,6 +9,7 @@ import audio_service import audio_session import device_info_plus import dynamic_color +import file_picker import just_audio import package_info_plus import path_provider_foundation @@ -24,6 +25,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { AudioSessionPlugin.register(with: registry.registrar(forPlugin: "AudioSessionPlugin")) DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin")) DynamicColorPlugin.register(with: registry.registrar(forPlugin: "DynamicColorPlugin")) + FilePickerPlugin.register(with: registry.registrar(forPlugin: "FilePickerPlugin")) JustAudioPlugin.register(with: registry.registrar(forPlugin: "JustAudioPlugin")) FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) diff --git a/pubspec.lock b/pubspec.lock index 4d69630..501feaf 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,26 +5,31 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - sha256: da0d9209ca76bde579f2da330aeb9df62b6319c834fa7baae052021b0462401f + sha256: "16e298750b6d0af7ce8a3ba7c18c69c3785d11b15ec83f6dcd0ad2a0009b3cab" url: "https://pub.dev" source: hosted - version: "85.0.0" + version: "76.0.0" + _macros: + dependency: transitive + description: dart + source: sdk + version: "0.3.3" analyzer: dependency: transitive description: name: analyzer - sha256: f4ad0fea5f102201015c9aae9d93bc02f75dd9491529a8c21f88d17a8523d44c + sha256: "1f14db053a8c23e260789e9b0980fa27f2680dd640932cae5e1137cce0e46e1e" url: "https://pub.dev" source: hosted - version: "7.6.0" + version: "6.11.0" analyzer_plugin: dependency: transitive description: name: analyzer_plugin - sha256: "1d460d14e3c2ae36dc2b32cef847c4479198cf87704f63c3c3c8150ee50c3916" + sha256: "9661b30b13a685efaee9f02e5d01ed9f2b423bd889d28a304d02d704aee69161" url: "https://pub.dev" source: hosted - version: "0.12.0" + version: "0.11.3" animated_list_plus: dependency: "direct main" description: @@ -301,42 +306,50 @@ packages: dependency: "direct dev" description: name: custom_lint - sha256: "021897cce2b6c783b2521543e362e7fe1a2eaab17bf80514d8de37f99942ed9e" + sha256: "3486c470bb93313a9417f926c7dd694a2e349220992d7b9d14534dc49c15bba9" url: "https://pub.dev" source: hosted - version: "0.7.3" + version: "0.7.0" custom_lint_builder: dependency: transitive description: name: custom_lint_builder - sha256: e4235b9d8cef59afe621eba086d245205c8a0a6c70cd470be7cb17494d6df32d + sha256: "42cdc41994eeeddab0d7a722c7093ec52bd0761921eeb2cbdbf33d192a234759" url: "https://pub.dev" source: hosted - version: "0.7.3" + version: "0.7.0" custom_lint_core: dependency: transitive description: name: custom_lint_core - sha256: "6dcee8a017181941c51a110da7e267c1d104dc74bec8862eeb8c85b5c8759a9e" + sha256: "02450c3e45e2a6e8b26c4d16687596ab3c4644dd5792e3313aa9ceba5a49b7f5" url: "https://pub.dev" source: hosted - version: "0.7.1" + version: "0.7.0" custom_lint_visitor: dependency: transitive description: name: custom_lint_visitor - sha256: "4a86a0d8415a91fbb8298d6ef03e9034dc8e323a599ddc4120a0e36c433983a2" + sha256: bfe9b7a09c4775a587b58d10ebb871d4fe618237639b1e84d5ec62d7dfef25f9 url: "https://pub.dev" source: hosted - version: "1.0.0+7.7.0" + version: "1.0.0+6.11.0" dart_style: dependency: transitive description: name: dart_style - sha256: "8a0e5fba27e8ee025d2ffb4ee820b4e6e2cf5e4246a6b1a477eb66866947e0bb" + sha256: "7306ab8a2359a48d22310ad823521d723acfed60ee1f7e37388e8986853b6820" url: "https://pub.dev" source: hosted - version: "3.1.1" + version: "2.3.8" + dbus: + dependency: transitive + description: + name: dbus + sha256: "79e0c23480ff85dc68de79e2cd6334add97e48f7f4865d17686dd6ea81a47e8c" + url: "https://pub.dev" + source: hosted + version: "0.7.11" device_info_plus: dependency: "direct main" description: @@ -409,6 +422,14 @@ packages: url: "https://pub.dev" source: hosted version: "7.0.1" + file_picker: + dependency: "direct main" + description: + name: file_picker + sha256: d974b6ba2606371ac71dd94254beefb6fa81185bde0b59bdc1df09885da85fde + url: "https://pub.dev" + source: hosted + version: "10.3.8" fixnum: dependency: transitive description: @@ -475,6 +496,14 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_plugin_android_lifecycle: + dependency: transitive + description: + name: flutter_plugin_android_lifecycle + sha256: c2fe1001710127dfa7da89977a08d591398370d099aacdaa6d44da7eb14b8476 + url: "https://pub.dev" + source: hosted + version: "2.0.31" flutter_riverpod: dependency: transitive description: @@ -529,10 +558,10 @@ packages: dependency: "direct dev" description: name: freezed - sha256: "59a584c24b3acdc5250bb856d0d3e9c0b798ed14a4af1ddb7dc1c7b41df91c9c" + sha256: "44c19278dd9d89292cf46e97dc0c1e52ce03275f40a97c5a348e802a924bf40e" url: "https://pub.dev" source: hosted - version: "2.5.8" + version: "2.5.7" freezed_annotation: dependency: "direct main" description: @@ -593,10 +622,10 @@ packages: dependency: "direct dev" description: name: hive_ce_generator - sha256: "609678c10ebee7503505a0007050af40a0a4f498b1fb7def3220df341e573a89" + sha256: "182fb88273055e05ef0e630b5e32e5a30268722ed3bf46fdf5986792862975af" url: "https://pub.dev" source: hosted - version: "1.9.2" + version: "1.8.1" hooks_riverpod: dependency: "direct main" description: @@ -689,10 +718,10 @@ packages: dependency: transitive description: name: js - sha256: "53385261521cc4a0c4658fd0ad07a7d14591cf8fc33abbceae306ddb974888dc" + sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 url: "https://pub.dev" source: hosted - version: "0.7.2" + version: "0.6.7" json_annotation: dependency: "direct main" description: @@ -705,10 +734,10 @@ packages: dependency: "direct dev" description: name: json_serializable - sha256: c50ef5fc083d5b5e12eef489503ba3bf5ccc899e487d691584699b4bdefeea8c + sha256: c2fcb3920cf2b6ae6845954186420fca40bc0a8abcc84903b7801f17d7050d7c url: "https://pub.dev" source: hosted - version: "6.9.5" + version: "6.9.0" just_audio: dependency: "direct main" description: @@ -785,10 +814,10 @@ packages: dependency: "direct main" description: name: list_wheel_scroll_view_nls - sha256: d4c6d654d811776e239a2c49c8e26f5ae63bde31e6827011375bd76170b197ac + sha256: "47a6c27dac35768f2bcd0db05a31f04347ea116faf3529131d937cf130c36e91" url: "https://pub.dev" source: hosted - version: "0.0.5" + version: "0.0.3" logging: dependency: "direct main" description: @@ -813,6 +842,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.3.1" + macros: + dependency: transitive + description: + name: macros + sha256: "1d9e801cd66f7ea3663c45fc708450db1fa57f988142c64289142c9b7ee80656" + url: "https://pub.dev" + source: hosted + version: "0.1.3-main.0" matcher: dependency: transitive description: @@ -1089,10 +1126,10 @@ packages: dependency: transitive description: name: riverpod_analyzer_utils - sha256: "837a6dc33f490706c7f4632c516bcd10804ee4d9ccc8046124ca56388715fdf3" + sha256: c6b8222b2b483cb87ae77ad147d6408f400c64f060df7a225b127f4afef4f8c8 url: "https://pub.dev" source: hosted - version: "0.5.9" + version: "0.5.8" riverpod_annotation: dependency: "direct main" description: @@ -1105,18 +1142,18 @@ packages: dependency: "direct dev" description: name: riverpod_generator - sha256: "120d3310f687f43e7011bb213b90a436f1bbc300f0e4b251a72c39bccb017a4f" + sha256: "63546d70952015f0981361636bf8f356d9cfd9d7f6f0815e3c07789a41233188" url: "https://pub.dev" source: hosted - version: "2.6.4" + version: "2.6.3" riverpod_lint: dependency: "direct dev" description: name: riverpod_lint - sha256: b05408412b0f75dec954e032c855bc28349eeed2d2187f94519e1ddfdf8b3693 + sha256: "83e4caa337a9840469b7b9bd8c2351ce85abad80f570d84146911b32086fbd99" url: "https://pub.dev" source: hosted - version: "2.6.4" + version: "2.6.3" rxdart: dependency: transitive description: @@ -1277,18 +1314,18 @@ packages: dependency: transitive description: name: source_gen - sha256: "35c8150ece9e8c8d263337a265153c3329667640850b9304861faea59fc98f6b" + sha256: "14658ba5f669685cd3d63701d01b31ea748310f7ab854e471962670abcf57832" url: "https://pub.dev" source: hosted - version: "2.0.0" + version: "1.5.0" source_helper: dependency: transitive description: name: source_helper - sha256: a447acb083d3a5ef17f983dd36201aeea33fedadb3228fa831f2f0c92f0f3aca + sha256: "86d247119aedce8e63f4751bd9626fc9613255935558447569ad42f9f5b48b3c" url: "https://pub.dev" source: hosted - version: "1.3.7" + version: "1.3.5" source_span: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index f0d5133..0bb2ffc 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -52,7 +52,7 @@ dependencies: duration_picker: ^1.2.0 dynamic_color: ^1.7.0 # easy_stepper: ^0.8.4 - # file_picker: ^10.0.0 + file_picker: ^10.0.0 flutter_animate: ^4.5.0 flutter_cache_manager: ^3.3.2