mirror of
https://github.com/Dr-Blank/Vaani.git
synced 2026-02-17 23:09:36 +00:00
123
This commit is contained in:
parent
6ffd76a194
commit
b0f5dd8951
18 changed files with 441 additions and 64 deletions
|
|
@ -54,5 +54,10 @@
|
||||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||||
</array>
|
</array>
|
||||||
|
|
||||||
|
<key>LSSupportsOpeningDocumentsInPlace</key>
|
||||||
|
<true/>
|
||||||
|
<key>UIFileSharingEnabled</key>
|
||||||
|
<true/>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ class AudiobookDownloadManager {
|
||||||
this.requiresWiFi = true,
|
this.requiresWiFi = true,
|
||||||
this.retries = 0,
|
this.retries = 0,
|
||||||
this.allowPause = false,
|
this.allowPause = false,
|
||||||
|
this.path = '',
|
||||||
|
|
||||||
// /// The maximum number of concurrent tasks to run at any given time.
|
// /// The maximum number of concurrent tasks to run at any given time.
|
||||||
// int maxConcurrent = 3,
|
// int maxConcurrent = 3,
|
||||||
|
|
@ -60,6 +61,9 @@ class AudiobookDownloadManager {
|
||||||
// whether to allow pausing of downloads
|
// whether to allow pausing of downloads
|
||||||
final bool allowPause;
|
final bool allowPause;
|
||||||
|
|
||||||
|
// 下载目录
|
||||||
|
final String path;
|
||||||
|
|
||||||
final StreamController<TaskUpdate> _taskStatusController =
|
final StreamController<TaskUpdate> _taskStatusController =
|
||||||
StreamController.broadcast();
|
StreamController.broadcast();
|
||||||
|
|
||||||
|
|
@ -68,11 +72,16 @@ class AudiobookDownloadManager {
|
||||||
late StreamSubscription<TaskUpdate> _updatesSubscription;
|
late StreamSubscription<TaskUpdate> _updatesSubscription;
|
||||||
|
|
||||||
Future<void> queueAudioBookDownload(
|
Future<void> queueAudioBookDownload(
|
||||||
LibraryItemExpanded item,
|
LibraryItemExpanded item, {
|
||||||
) async {
|
String prePath = '',
|
||||||
|
}) async {
|
||||||
_logger.info('queuing download for item: ${item.id}');
|
_logger.info('queuing download for item: ${item.id}');
|
||||||
// create a download task for each file in the item
|
// create a download task for each file in the item
|
||||||
for (final file in item.libraryFiles) {
|
for (final file in item.libraryFiles) {
|
||||||
|
// 仅下载音频和视频
|
||||||
|
if (![FileType.audio, FileType.video].contains(file.fileType)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
// check if the file is already downloaded
|
// check if the file is already downloaded
|
||||||
if (isFileDownloaded(
|
if (isFileDownloaded(
|
||||||
constructFilePath(item, file),
|
constructFilePath(item, file),
|
||||||
|
|
@ -84,7 +93,7 @@ class AudiobookDownloadManager {
|
||||||
final task = DownloadTask(
|
final task = DownloadTask(
|
||||||
taskId: file.ino,
|
taskId: file.ino,
|
||||||
url: file.url(baseUrl, item.id, token).toString(),
|
url: file.url(baseUrl, item.id, token).toString(),
|
||||||
directory: item.relPath,
|
directory: prePath + item.relPath,
|
||||||
filename: file.metadata.filename,
|
filename: file.metadata.filename,
|
||||||
requiresWiFi: requiresWiFi,
|
requiresWiFi: requiresWiFi,
|
||||||
retries: retries,
|
retries: retries,
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:background_downloader/background_downloader.dart';
|
import 'package:background_downloader/background_downloader.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:logging/logging.dart';
|
import 'package:logging/logging.dart';
|
||||||
|
|
@ -26,6 +28,7 @@ class SimpleDownloadManager extends _$SimpleDownloadManager {
|
||||||
requiresWiFi: downloadSettings.requiresWiFi,
|
requiresWiFi: downloadSettings.requiresWiFi,
|
||||||
retries: downloadSettings.retries,
|
retries: downloadSettings.retries,
|
||||||
allowPause: downloadSettings.allowPause,
|
allowPause: downloadSettings.allowPause,
|
||||||
|
path: downloadSettings.path,
|
||||||
);
|
);
|
||||||
core.tq.maxConcurrent = downloadSettings.maxConcurrent;
|
core.tq.maxConcurrent = downloadSettings.maxConcurrent;
|
||||||
core.tq.maxConcurrentByHost = downloadSettings.maxConcurrentByHost;
|
core.tq.maxConcurrentByHost = downloadSettings.maxConcurrentByHost;
|
||||||
|
|
@ -56,6 +59,8 @@ class DownloadManager extends _$DownloadManager {
|
||||||
LibraryItemExpanded item,
|
LibraryItemExpanded item,
|
||||||
) async {
|
) async {
|
||||||
_logger.fine('queueing download for ${item.id}');
|
_logger.fine('queueing download for ${item.id}');
|
||||||
|
// final appSettings = ref.read(appSettingsProvider);
|
||||||
|
|
||||||
await state.queueAudioBookDownload(
|
await state.queueAudioBookDownload(
|
||||||
item,
|
item,
|
||||||
);
|
);
|
||||||
|
|
@ -66,6 +71,24 @@ class DownloadManager extends _$DownloadManager {
|
||||||
await state.deleteDownloadedItem(item);
|
await state.deleteDownloadedItem(item);
|
||||||
ref.notifyListeners();
|
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
|
@riverpod
|
||||||
|
|
|
||||||
|
|
@ -160,7 +160,7 @@ class _DownloadHistoryProviderElement
|
||||||
}
|
}
|
||||||
|
|
||||||
String _$simpleDownloadManagerHash() =>
|
String _$simpleDownloadManagerHash() =>
|
||||||
r'8ab13f06ec5f2f73b73064bd285813dc890b7f36';
|
r'da5798e4becce751db80c41b93a48217418e4648';
|
||||||
|
|
||||||
/// See also [SimpleDownloadManager].
|
/// See also [SimpleDownloadManager].
|
||||||
@ProviderFor(SimpleDownloadManager)
|
@ProviderFor(SimpleDownloadManager)
|
||||||
|
|
@ -176,7 +176,7 @@ final simpleDownloadManagerProvider = NotifierProvider<SimpleDownloadManager,
|
||||||
);
|
);
|
||||||
|
|
||||||
typedef _$SimpleDownloadManager = Notifier<core.AudiobookDownloadManager>;
|
typedef _$SimpleDownloadManager = Notifier<core.AudiobookDownloadManager>;
|
||||||
String _$downloadManagerHash() => r'852012e32e613f86445afc7f7e4e85bec808e982';
|
String _$downloadManagerHash() => r'92afe484d6735d5de53473011ea9ecbad107fc1c';
|
||||||
|
|
||||||
/// See also [DownloadManager].
|
/// See also [DownloadManager].
|
||||||
@ProviderFor(DownloadManager)
|
@ProviderFor(DownloadManager)
|
||||||
|
|
|
||||||
|
|
@ -94,7 +94,7 @@ class LibraryItemActions extends HookConsumerWidget {
|
||||||
},
|
},
|
||||||
icon: const Icon(Icons.share_rounded),
|
icon: const Icon(Icons.share_rounded),
|
||||||
),
|
),
|
||||||
LibItemDownButton(item.id),
|
LibItemDownButton(item: item),
|
||||||
// download button
|
// download button
|
||||||
LibItemDownloadButton(item: item),
|
LibItemDownloadButton(item: item),
|
||||||
|
|
||||||
|
|
@ -205,8 +205,8 @@ class LibraryItemActions extends HookConsumerWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
class LibItemDownButton extends HookConsumerWidget {
|
class LibItemDownButton extends HookConsumerWidget {
|
||||||
const LibItemDownButton(this.libraryItemId, {super.key});
|
const LibItemDownButton({required this.item, super.key});
|
||||||
final String libraryItemId;
|
final shelfsdk.LibraryItemExpanded item;
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
return IconButton(
|
return IconButton(
|
||||||
|
|
@ -217,7 +217,7 @@ class LibItemDownButton extends HookConsumerWidget {
|
||||||
builder: (context) {
|
builder: (context) {
|
||||||
return FractionallySizedBox(
|
return FractionallySizedBox(
|
||||||
heightFactor: 0.8,
|
heightFactor: 0.8,
|
||||||
child: LibItemDownSheet(libraryItemId),
|
child: LibItemDownSheet(item.id),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
@ -253,13 +253,17 @@ class LibItemDownSheet extends HookConsumerWidget {
|
||||||
mainAxisAlignment: MainAxisAlignment.end,
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
children: [
|
children: [
|
||||||
IconButton(
|
IconButton(
|
||||||
onPressed: () {},
|
onPressed: () {
|
||||||
|
appLogger.fine('Pressed delete download button');
|
||||||
|
ref
|
||||||
|
.read(downloadManagerProvider.notifier)
|
||||||
|
.deleteDownloadedItem(
|
||||||
|
item,
|
||||||
|
);
|
||||||
|
},
|
||||||
icon: Icon(Icons.delete_outlined),
|
icon: Icon(Icons.delete_outlined),
|
||||||
),
|
),
|
||||||
IconButton(
|
LibItemDownloadButton(item: item),
|
||||||
onPressed: () {},
|
|
||||||
icon: Icon(Icons.download_outlined),
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -275,7 +275,7 @@ final playerStateProvider =
|
||||||
);
|
);
|
||||||
|
|
||||||
typedef _$PlayerState = AutoDisposeNotifier<core.AbsPlayerState>;
|
typedef _$PlayerState = AutoDisposeNotifier<core.AbsPlayerState>;
|
||||||
String _$currentBookHash() => r'b4f6b6ccc772631db3dfd9070be3d7487333544d';
|
String _$currentBookHash() => r'790af1f9502b12879fc22c900ed5e3572381ab1e';
|
||||||
|
|
||||||
/// See also [CurrentBook].
|
/// See also [CurrentBook].
|
||||||
@ProviderFor(CurrentBook)
|
@ProviderFor(CurrentBook)
|
||||||
|
|
|
||||||
|
|
@ -101,7 +101,9 @@ class PlayerExpandedDesktop extends HookConsumerWidget {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
child: ChapterSelectionModal(),
|
child: ChapterSelectionModal(
|
||||||
|
back: false,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,9 @@ class ChapterSelectionButton extends HookConsumerWidget {
|
||||||
class ChapterSelectionModal extends HookConsumerWidget {
|
class ChapterSelectionModal extends HookConsumerWidget {
|
||||||
const ChapterSelectionModal({
|
const ChapterSelectionModal({
|
||||||
super.key,
|
super.key,
|
||||||
|
this.back = true,
|
||||||
});
|
});
|
||||||
|
final bool back;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
|
@ -108,8 +110,11 @@ class ChapterSelectionModal extends HookConsumerWidget {
|
||||||
: const Icon(Icons.play_arrow),
|
: const Icon(Icons.play_arrow),
|
||||||
selected: isCurrent,
|
selected: isCurrent,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
Navigator.of(context).pop();
|
if (back) {
|
||||||
ref.read(absPlayerProvider).switchChapter(chapter.id);
|
Navigator.of(context).pop();
|
||||||
|
} else {
|
||||||
|
ref.read(absPlayerProvider).switchChapter(chapter.id);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -143,6 +143,7 @@ class DownloadSettings with _$DownloadSettings {
|
||||||
@Default(3) int maxConcurrent,
|
@Default(3) int maxConcurrent,
|
||||||
@Default(3) int maxConcurrentByHost,
|
@Default(3) int maxConcurrentByHost,
|
||||||
@Default(3) int maxConcurrentByGroup,
|
@Default(3) int maxConcurrentByGroup,
|
||||||
|
@Default('') String path,
|
||||||
}) = _DownloadSettings;
|
}) = _DownloadSettings;
|
||||||
|
|
||||||
factory DownloadSettings.fromJson(Map<String, dynamic> json) =>
|
factory DownloadSettings.fromJson(Map<String, dynamic> json) =>
|
||||||
|
|
|
||||||
|
|
@ -1970,6 +1970,7 @@ mixin _$DownloadSettings {
|
||||||
int get maxConcurrent => throw _privateConstructorUsedError;
|
int get maxConcurrent => throw _privateConstructorUsedError;
|
||||||
int get maxConcurrentByHost => throw _privateConstructorUsedError;
|
int get maxConcurrentByHost => throw _privateConstructorUsedError;
|
||||||
int get maxConcurrentByGroup => throw _privateConstructorUsedError;
|
int get maxConcurrentByGroup => throw _privateConstructorUsedError;
|
||||||
|
String get path => throw _privateConstructorUsedError;
|
||||||
|
|
||||||
/// Serializes this DownloadSettings to a JSON map.
|
/// Serializes this DownloadSettings to a JSON map.
|
||||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||||
|
|
@ -1993,7 +1994,8 @@ abstract class $DownloadSettingsCopyWith<$Res> {
|
||||||
bool allowPause,
|
bool allowPause,
|
||||||
int maxConcurrent,
|
int maxConcurrent,
|
||||||
int maxConcurrentByHost,
|
int maxConcurrentByHost,
|
||||||
int maxConcurrentByGroup});
|
int maxConcurrentByGroup,
|
||||||
|
String path});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @nodoc
|
/// @nodoc
|
||||||
|
|
@ -2017,6 +2019,7 @@ class _$DownloadSettingsCopyWithImpl<$Res, $Val extends DownloadSettings>
|
||||||
Object? maxConcurrent = null,
|
Object? maxConcurrent = null,
|
||||||
Object? maxConcurrentByHost = null,
|
Object? maxConcurrentByHost = null,
|
||||||
Object? maxConcurrentByGroup = null,
|
Object? maxConcurrentByGroup = null,
|
||||||
|
Object? path = null,
|
||||||
}) {
|
}) {
|
||||||
return _then(_value.copyWith(
|
return _then(_value.copyWith(
|
||||||
requiresWiFi: null == requiresWiFi
|
requiresWiFi: null == requiresWiFi
|
||||||
|
|
@ -2043,6 +2046,10 @@ class _$DownloadSettingsCopyWithImpl<$Res, $Val extends DownloadSettings>
|
||||||
? _value.maxConcurrentByGroup
|
? _value.maxConcurrentByGroup
|
||||||
: maxConcurrentByGroup // ignore: cast_nullable_to_non_nullable
|
: maxConcurrentByGroup // ignore: cast_nullable_to_non_nullable
|
||||||
as int,
|
as int,
|
||||||
|
path: null == path
|
||||||
|
? _value.path
|
||||||
|
: path // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
) as $Val);
|
) as $Val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2061,7 +2068,8 @@ abstract class _$$DownloadSettingsImplCopyWith<$Res>
|
||||||
bool allowPause,
|
bool allowPause,
|
||||||
int maxConcurrent,
|
int maxConcurrent,
|
||||||
int maxConcurrentByHost,
|
int maxConcurrentByHost,
|
||||||
int maxConcurrentByGroup});
|
int maxConcurrentByGroup,
|
||||||
|
String path});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @nodoc
|
/// @nodoc
|
||||||
|
|
@ -2083,6 +2091,7 @@ class __$$DownloadSettingsImplCopyWithImpl<$Res>
|
||||||
Object? maxConcurrent = null,
|
Object? maxConcurrent = null,
|
||||||
Object? maxConcurrentByHost = null,
|
Object? maxConcurrentByHost = null,
|
||||||
Object? maxConcurrentByGroup = null,
|
Object? maxConcurrentByGroup = null,
|
||||||
|
Object? path = null,
|
||||||
}) {
|
}) {
|
||||||
return _then(_$DownloadSettingsImpl(
|
return _then(_$DownloadSettingsImpl(
|
||||||
requiresWiFi: null == requiresWiFi
|
requiresWiFi: null == requiresWiFi
|
||||||
|
|
@ -2109,6 +2118,10 @@ class __$$DownloadSettingsImplCopyWithImpl<$Res>
|
||||||
? _value.maxConcurrentByGroup
|
? _value.maxConcurrentByGroup
|
||||||
: maxConcurrentByGroup // ignore: cast_nullable_to_non_nullable
|
: maxConcurrentByGroup // ignore: cast_nullable_to_non_nullable
|
||||||
as int,
|
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.allowPause = true,
|
||||||
this.maxConcurrent = 3,
|
this.maxConcurrent = 3,
|
||||||
this.maxConcurrentByHost = 3,
|
this.maxConcurrentByHost = 3,
|
||||||
this.maxConcurrentByGroup = 3});
|
this.maxConcurrentByGroup = 3,
|
||||||
|
this.path = ''});
|
||||||
|
|
||||||
factory _$DownloadSettingsImpl.fromJson(Map<String, dynamic> json) =>
|
factory _$DownloadSettingsImpl.fromJson(Map<String, dynamic> json) =>
|
||||||
_$$DownloadSettingsImplFromJson(json);
|
_$$DownloadSettingsImplFromJson(json);
|
||||||
|
|
@ -2145,10 +2159,13 @@ class _$DownloadSettingsImpl implements _DownloadSettings {
|
||||||
@override
|
@override
|
||||||
@JsonKey()
|
@JsonKey()
|
||||||
final int maxConcurrentByGroup;
|
final int maxConcurrentByGroup;
|
||||||
|
@override
|
||||||
|
@JsonKey()
|
||||||
|
final String path;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
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
|
@override
|
||||||
|
|
@ -2166,13 +2183,21 @@ class _$DownloadSettingsImpl implements _DownloadSettings {
|
||||||
(identical(other.maxConcurrentByHost, maxConcurrentByHost) ||
|
(identical(other.maxConcurrentByHost, maxConcurrentByHost) ||
|
||||||
other.maxConcurrentByHost == maxConcurrentByHost) &&
|
other.maxConcurrentByHost == maxConcurrentByHost) &&
|
||||||
(identical(other.maxConcurrentByGroup, maxConcurrentByGroup) ||
|
(identical(other.maxConcurrentByGroup, maxConcurrentByGroup) ||
|
||||||
other.maxConcurrentByGroup == maxConcurrentByGroup));
|
other.maxConcurrentByGroup == maxConcurrentByGroup) &&
|
||||||
|
(identical(other.path, path) || other.path == path));
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
@override
|
@override
|
||||||
int get hashCode => Object.hash(runtimeType, requiresWiFi, retries,
|
int get hashCode => Object.hash(
|
||||||
allowPause, maxConcurrent, maxConcurrentByHost, maxConcurrentByGroup);
|
runtimeType,
|
||||||
|
requiresWiFi,
|
||||||
|
retries,
|
||||||
|
allowPause,
|
||||||
|
maxConcurrent,
|
||||||
|
maxConcurrentByHost,
|
||||||
|
maxConcurrentByGroup,
|
||||||
|
path);
|
||||||
|
|
||||||
/// Create a copy of DownloadSettings
|
/// Create a copy of DownloadSettings
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
|
@ -2198,7 +2223,8 @@ abstract class _DownloadSettings implements DownloadSettings {
|
||||||
final bool allowPause,
|
final bool allowPause,
|
||||||
final int maxConcurrent,
|
final int maxConcurrent,
|
||||||
final int maxConcurrentByHost,
|
final int maxConcurrentByHost,
|
||||||
final int maxConcurrentByGroup}) = _$DownloadSettingsImpl;
|
final int maxConcurrentByGroup,
|
||||||
|
final String path}) = _$DownloadSettingsImpl;
|
||||||
|
|
||||||
factory _DownloadSettings.fromJson(Map<String, dynamic> json) =
|
factory _DownloadSettings.fromJson(Map<String, dynamic> json) =
|
||||||
_$DownloadSettingsImpl.fromJson;
|
_$DownloadSettingsImpl.fromJson;
|
||||||
|
|
@ -2215,6 +2241,8 @@ abstract class _DownloadSettings implements DownloadSettings {
|
||||||
int get maxConcurrentByHost;
|
int get maxConcurrentByHost;
|
||||||
@override
|
@override
|
||||||
int get maxConcurrentByGroup;
|
int get maxConcurrentByGroup;
|
||||||
|
@override
|
||||||
|
String get path;
|
||||||
|
|
||||||
/// Create a copy of DownloadSettings
|
/// Create a copy of DownloadSettings
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
|
|
||||||
|
|
@ -239,6 +239,7 @@ _$DownloadSettingsImpl _$$DownloadSettingsImplFromJson(
|
||||||
maxConcurrentByHost: (json['maxConcurrentByHost'] as num?)?.toInt() ?? 3,
|
maxConcurrentByHost: (json['maxConcurrentByHost'] as num?)?.toInt() ?? 3,
|
||||||
maxConcurrentByGroup:
|
maxConcurrentByGroup:
|
||||||
(json['maxConcurrentByGroup'] as num?)?.toInt() ?? 3,
|
(json['maxConcurrentByGroup'] as num?)?.toInt() ?? 3,
|
||||||
|
path: json['path'] as String? ?? '',
|
||||||
);
|
);
|
||||||
|
|
||||||
Map<String, dynamic> _$$DownloadSettingsImplToJson(
|
Map<String, dynamic> _$$DownloadSettingsImplToJson(
|
||||||
|
|
@ -250,6 +251,7 @@ Map<String, dynamic> _$$DownloadSettingsImplToJson(
|
||||||
'maxConcurrent': instance.maxConcurrent,
|
'maxConcurrent': instance.maxConcurrent,
|
||||||
'maxConcurrentByHost': instance.maxConcurrentByHost,
|
'maxConcurrentByHost': instance.maxConcurrentByHost,
|
||||||
'maxConcurrentByGroup': instance.maxConcurrentByGroup,
|
'maxConcurrentByGroup': instance.maxConcurrentByGroup,
|
||||||
|
'path': instance.path,
|
||||||
};
|
};
|
||||||
|
|
||||||
_$NotificationSettingsImpl _$$NotificationSettingsImplFromJson(
|
_$NotificationSettingsImpl _$$NotificationSettingsImplFromJson(
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ class AppSettingsPage extends HookConsumerWidget {
|
||||||
tiles: [
|
tiles: [
|
||||||
SettingsTile(
|
SettingsTile(
|
||||||
title: Text(S.of(context).language),
|
title: Text(S.of(context).language),
|
||||||
leading: const Icon(Icons.play_arrow),
|
leading: const Icon(Icons.language),
|
||||||
trailing: DropdownButton(
|
trailing: DropdownButton(
|
||||||
value: appSettings.language,
|
value: appSettings.language,
|
||||||
items: S.delegate.supportedLocales.map((locale) {
|
items: S.delegate.supportedLocales.map((locale) {
|
||||||
|
|
@ -66,6 +66,14 @@ class AppSettingsPage extends HookConsumerWidget {
|
||||||
context.pushNamed(Routes.playerSettings.name);
|
context.pushNamed(Routes.playerSettings.name);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
SettingsTile(
|
||||||
|
title: Text('下载设置'),
|
||||||
|
leading: const Icon(Icons.download),
|
||||||
|
description: Text('自定义下载设置'),
|
||||||
|
onPressed: (context) {
|
||||||
|
context.pushNamed(Routes.downloadSettings.name);
|
||||||
|
},
|
||||||
|
),
|
||||||
NavigationWithSwitchTile(
|
NavigationWithSwitchTile(
|
||||||
title: Text(S.of(context).autoTurnOnSleepTimer),
|
title: Text(S.of(context).autoTurnOnSleepTimer),
|
||||||
description: Text(S.of(context).automaticallyDescription),
|
description: Text(S.of(context).automaticallyDescription),
|
||||||
|
|
|
||||||
239
lib/features/settings/view/download_settings_page.dart
Normal file
239
lib/features/settings/view/download_settings_page.dart
Normal file
|
|
@ -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<double?>(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<double> initialValue;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final speedOptionAddController = useTextEditingController();
|
||||||
|
final speedOptions = useState<List<double>>(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);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -47,6 +47,11 @@ class Routes {
|
||||||
name: 'playerSettings',
|
name: 'playerSettings',
|
||||||
parentRoute: settings,
|
parentRoute: settings,
|
||||||
);
|
);
|
||||||
|
static const downloadSettings = _SimpleRoute(
|
||||||
|
pathName: 'downloadSettings',
|
||||||
|
name: 'downloadSettings',
|
||||||
|
parentRoute: settings,
|
||||||
|
);
|
||||||
static const shakeDetectorSettings = _SimpleRoute(
|
static const shakeDetectorSettings = _SimpleRoute(
|
||||||
pathName: 'shakeDetector',
|
pathName: 'shakeDetector',
|
||||||
name: 'shakeDetectorSettings',
|
name: 'shakeDetectorSettings',
|
||||||
|
|
|
||||||
|
|
@ -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/onboarding/view/onboarding_single_page.dart';
|
||||||
import 'package:vaani/features/settings/view/app_settings_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/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/home_page_settings_page.dart';
|
||||||
import 'package:vaani/features/settings/view/notification_settings_page.dart';
|
import 'package:vaani/features/settings/view/notification_settings_page.dart';
|
||||||
import 'package:vaani/features/settings/view/player_settings_page.dart';
|
import 'package:vaani/features/settings/view/player_settings_page.dart';
|
||||||
|
|
@ -213,6 +214,12 @@ class MyAppRouter {
|
||||||
pageBuilder:
|
pageBuilder:
|
||||||
defaultPageBuilder(const PlayerSettingsPage()),
|
defaultPageBuilder(const PlayerSettingsPage()),
|
||||||
),
|
),
|
||||||
|
GoRoute(
|
||||||
|
path: Routes.downloadSettings.pathName,
|
||||||
|
name: Routes.downloadSettings.name,
|
||||||
|
pageBuilder:
|
||||||
|
defaultPageBuilder(const DownloadSettingsPage()),
|
||||||
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: Routes.shakeDetectorSettings.pathName,
|
path: Routes.shakeDetectorSettings.pathName,
|
||||||
name: Routes.shakeDetectorSettings.name,
|
name: Routes.shakeDetectorSettings.name,
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import audio_service
|
||||||
import audio_session
|
import audio_session
|
||||||
import device_info_plus
|
import device_info_plus
|
||||||
import dynamic_color
|
import dynamic_color
|
||||||
|
import file_picker
|
||||||
import just_audio
|
import just_audio
|
||||||
import package_info_plus
|
import package_info_plus
|
||||||
import path_provider_foundation
|
import path_provider_foundation
|
||||||
|
|
@ -24,6 +25,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||||
AudioSessionPlugin.register(with: registry.registrar(forPlugin: "AudioSessionPlugin"))
|
AudioSessionPlugin.register(with: registry.registrar(forPlugin: "AudioSessionPlugin"))
|
||||||
DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin"))
|
DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin"))
|
||||||
DynamicColorPlugin.register(with: registry.registrar(forPlugin: "DynamicColorPlugin"))
|
DynamicColorPlugin.register(with: registry.registrar(forPlugin: "DynamicColorPlugin"))
|
||||||
|
FilePickerPlugin.register(with: registry.registrar(forPlugin: "FilePickerPlugin"))
|
||||||
JustAudioPlugin.register(with: registry.registrar(forPlugin: "JustAudioPlugin"))
|
JustAudioPlugin.register(with: registry.registrar(forPlugin: "JustAudioPlugin"))
|
||||||
FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin"))
|
FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin"))
|
||||||
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
||||||
|
|
|
||||||
109
pubspec.lock
109
pubspec.lock
|
|
@ -5,26 +5,31 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: _fe_analyzer_shared
|
name: _fe_analyzer_shared
|
||||||
sha256: da0d9209ca76bde579f2da330aeb9df62b6319c834fa7baae052021b0462401f
|
sha256: "16e298750b6d0af7ce8a3ba7c18c69c3785d11b15ec83f6dcd0ad2a0009b3cab"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "85.0.0"
|
version: "76.0.0"
|
||||||
|
_macros:
|
||||||
|
dependency: transitive
|
||||||
|
description: dart
|
||||||
|
source: sdk
|
||||||
|
version: "0.3.3"
|
||||||
analyzer:
|
analyzer:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: analyzer
|
name: analyzer
|
||||||
sha256: f4ad0fea5f102201015c9aae9d93bc02f75dd9491529a8c21f88d17a8523d44c
|
sha256: "1f14db053a8c23e260789e9b0980fa27f2680dd640932cae5e1137cce0e46e1e"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "7.6.0"
|
version: "6.11.0"
|
||||||
analyzer_plugin:
|
analyzer_plugin:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: analyzer_plugin
|
name: analyzer_plugin
|
||||||
sha256: "1d460d14e3c2ae36dc2b32cef847c4479198cf87704f63c3c3c8150ee50c3916"
|
sha256: "9661b30b13a685efaee9f02e5d01ed9f2b423bd889d28a304d02d704aee69161"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.12.0"
|
version: "0.11.3"
|
||||||
animated_list_plus:
|
animated_list_plus:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|
@ -301,42 +306,50 @@ packages:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
name: custom_lint
|
name: custom_lint
|
||||||
sha256: "021897cce2b6c783b2521543e362e7fe1a2eaab17bf80514d8de37f99942ed9e"
|
sha256: "3486c470bb93313a9417f926c7dd694a2e349220992d7b9d14534dc49c15bba9"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.7.3"
|
version: "0.7.0"
|
||||||
custom_lint_builder:
|
custom_lint_builder:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: custom_lint_builder
|
name: custom_lint_builder
|
||||||
sha256: e4235b9d8cef59afe621eba086d245205c8a0a6c70cd470be7cb17494d6df32d
|
sha256: "42cdc41994eeeddab0d7a722c7093ec52bd0761921eeb2cbdbf33d192a234759"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.7.3"
|
version: "0.7.0"
|
||||||
custom_lint_core:
|
custom_lint_core:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: custom_lint_core
|
name: custom_lint_core
|
||||||
sha256: "6dcee8a017181941c51a110da7e267c1d104dc74bec8862eeb8c85b5c8759a9e"
|
sha256: "02450c3e45e2a6e8b26c4d16687596ab3c4644dd5792e3313aa9ceba5a49b7f5"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.7.1"
|
version: "0.7.0"
|
||||||
custom_lint_visitor:
|
custom_lint_visitor:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: custom_lint_visitor
|
name: custom_lint_visitor
|
||||||
sha256: "4a86a0d8415a91fbb8298d6ef03e9034dc8e323a599ddc4120a0e36c433983a2"
|
sha256: bfe9b7a09c4775a587b58d10ebb871d4fe618237639b1e84d5ec62d7dfef25f9
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.0+7.7.0"
|
version: "1.0.0+6.11.0"
|
||||||
dart_style:
|
dart_style:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: dart_style
|
name: dart_style
|
||||||
sha256: "8a0e5fba27e8ee025d2ffb4ee820b4e6e2cf5e4246a6b1a477eb66866947e0bb"
|
sha256: "7306ab8a2359a48d22310ad823521d723acfed60ee1f7e37388e8986853b6820"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
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:
|
device_info_plus:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|
@ -409,6 +422,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "7.0.1"
|
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:
|
fixnum:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -475,6 +496,14 @@ packages:
|
||||||
description: flutter
|
description: flutter
|
||||||
source: sdk
|
source: sdk
|
||||||
version: "0.0.0"
|
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:
|
flutter_riverpod:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -529,10 +558,10 @@ packages:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
name: freezed
|
name: freezed
|
||||||
sha256: "59a584c24b3acdc5250bb856d0d3e9c0b798ed14a4af1ddb7dc1c7b41df91c9c"
|
sha256: "44c19278dd9d89292cf46e97dc0c1e52ce03275f40a97c5a348e802a924bf40e"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.5.8"
|
version: "2.5.7"
|
||||||
freezed_annotation:
|
freezed_annotation:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|
@ -593,10 +622,10 @@ packages:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
name: hive_ce_generator
|
name: hive_ce_generator
|
||||||
sha256: "609678c10ebee7503505a0007050af40a0a4f498b1fb7def3220df341e573a89"
|
sha256: "182fb88273055e05ef0e630b5e32e5a30268722ed3bf46fdf5986792862975af"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.9.2"
|
version: "1.8.1"
|
||||||
hooks_riverpod:
|
hooks_riverpod:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|
@ -689,10 +718,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: js
|
name: js
|
||||||
sha256: "53385261521cc4a0c4658fd0ad07a7d14591cf8fc33abbceae306ddb974888dc"
|
sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.7.2"
|
version: "0.6.7"
|
||||||
json_annotation:
|
json_annotation:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|
@ -705,10 +734,10 @@ packages:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
name: json_serializable
|
name: json_serializable
|
||||||
sha256: c50ef5fc083d5b5e12eef489503ba3bf5ccc899e487d691584699b4bdefeea8c
|
sha256: c2fcb3920cf2b6ae6845954186420fca40bc0a8abcc84903b7801f17d7050d7c
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.9.5"
|
version: "6.9.0"
|
||||||
just_audio:
|
just_audio:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|
@ -785,10 +814,10 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: list_wheel_scroll_view_nls
|
name: list_wheel_scroll_view_nls
|
||||||
sha256: d4c6d654d811776e239a2c49c8e26f5ae63bde31e6827011375bd76170b197ac
|
sha256: "47a6c27dac35768f2bcd0db05a31f04347ea116faf3529131d937cf130c36e91"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.0.5"
|
version: "0.0.3"
|
||||||
logging:
|
logging:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|
@ -813,6 +842,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.3.1"
|
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:
|
matcher:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -1089,10 +1126,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: riverpod_analyzer_utils
|
name: riverpod_analyzer_utils
|
||||||
sha256: "837a6dc33f490706c7f4632c516bcd10804ee4d9ccc8046124ca56388715fdf3"
|
sha256: c6b8222b2b483cb87ae77ad147d6408f400c64f060df7a225b127f4afef4f8c8
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.5.9"
|
version: "0.5.8"
|
||||||
riverpod_annotation:
|
riverpod_annotation:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|
@ -1105,18 +1142,18 @@ packages:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
name: riverpod_generator
|
name: riverpod_generator
|
||||||
sha256: "120d3310f687f43e7011bb213b90a436f1bbc300f0e4b251a72c39bccb017a4f"
|
sha256: "63546d70952015f0981361636bf8f356d9cfd9d7f6f0815e3c07789a41233188"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.6.4"
|
version: "2.6.3"
|
||||||
riverpod_lint:
|
riverpod_lint:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
name: riverpod_lint
|
name: riverpod_lint
|
||||||
sha256: b05408412b0f75dec954e032c855bc28349eeed2d2187f94519e1ddfdf8b3693
|
sha256: "83e4caa337a9840469b7b9bd8c2351ce85abad80f570d84146911b32086fbd99"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.6.4"
|
version: "2.6.3"
|
||||||
rxdart:
|
rxdart:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -1277,18 +1314,18 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: source_gen
|
name: source_gen
|
||||||
sha256: "35c8150ece9e8c8d263337a265153c3329667640850b9304861faea59fc98f6b"
|
sha256: "14658ba5f669685cd3d63701d01b31ea748310f7ab854e471962670abcf57832"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.0"
|
version: "1.5.0"
|
||||||
source_helper:
|
source_helper:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: source_helper
|
name: source_helper
|
||||||
sha256: a447acb083d3a5ef17f983dd36201aeea33fedadb3228fa831f2f0c92f0f3aca
|
sha256: "86d247119aedce8e63f4751bd9626fc9613255935558447569ad42f9f5b48b3c"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.3.7"
|
version: "1.3.5"
|
||||||
source_span:
|
source_span:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@ dependencies:
|
||||||
duration_picker: ^1.2.0
|
duration_picker: ^1.2.0
|
||||||
dynamic_color: ^1.7.0
|
dynamic_color: ^1.7.0
|
||||||
# easy_stepper: ^0.8.4
|
# easy_stepper: ^0.8.4
|
||||||
# file_picker: ^10.0.0
|
file_picker: ^10.0.0
|
||||||
|
|
||||||
flutter_animate: ^4.5.0
|
flutter_animate: ^4.5.0
|
||||||
flutter_cache_manager: ^3.3.2
|
flutter_cache_manager: ^3.3.2
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue