mirror of
https://github.com/Dr-Blank/Vaani.git
synced 2026-03-05 06:39:36 +00:00
Compare commits
3 commits
07aea41c6e
...
e23c0b6c5f
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e23c0b6c5f | ||
|
|
a520136e01 | ||
|
|
06694f5f0b |
148 changed files with 9317 additions and 11139 deletions
2
.fvmrc
2
.fvmrc
|
|
@ -1,3 +1,3 @@
|
|||
{
|
||||
"flutter": "3.32.0"
|
||||
"flutter": "3.38.6"
|
||||
}
|
||||
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
|
|
@ -22,7 +22,7 @@
|
|||
"utsname",
|
||||
"Vaani"
|
||||
],
|
||||
"dart.flutterSdkPath": ".fvm/versions/3.32.0",
|
||||
"dart.flutterSdkPath": ".fvm/versions/3.38.6",
|
||||
"files.exclude": {
|
||||
"**/*.freezed.dart": true,
|
||||
"**/*.g.dart": true
|
||||
|
|
|
|||
|
|
@ -31,10 +31,10 @@ if (keystorePropertiesFile.exists()) {
|
|||
android {
|
||||
namespace "dr.blank.vaani"
|
||||
compileSdk flutter.compileSdkVersion
|
||||
// ndkVersion flutter.ndkVersion
|
||||
ndkVersion flutter.ndkVersion
|
||||
// The NDK version is set to a specific version since it was not building
|
||||
// TODO remove when https://github.com/flutter/flutter/issues/139427 is closed
|
||||
ndkVersion = "29.0.13113456"
|
||||
// ndkVersion = "29.0.13113456"
|
||||
|
||||
|
||||
compileOptions {
|
||||
|
|
@ -64,7 +64,7 @@ android {
|
|||
applicationId "dr.blank.vaani"
|
||||
// You can update the following values to match your application needs.
|
||||
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
|
||||
minSdkVersion 23
|
||||
minSdkVersion flutter.minSdkVersion
|
||||
targetSdkVersion flutter.targetSdkVersion
|
||||
versionCode flutterVersionCode.toInteger()
|
||||
versionName flutterVersionName
|
||||
|
|
@ -100,4 +100,4 @@ configurations.all {
|
|||
force "androidx.core:core:1.13.1"
|
||||
force "androidx.core:core-ktx:1.13.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ pluginManagement {
|
|||
plugins {
|
||||
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
|
||||
id "com.android.application" version '8.10.0' apply false
|
||||
id "org.jetbrains.kotlin.android" version "2.0.20" apply false
|
||||
id "org.jetbrains.kotlin.android" version "2.1.10" apply false
|
||||
}
|
||||
|
||||
include ":app"
|
||||
|
|
|
|||
|
|
@ -16,10 +16,8 @@ import 'package:vaani/shared/extensions/obfuscation.dart';
|
|||
part 'api_provider.g.dart';
|
||||
|
||||
// TODO: workaround for https://github.com/rrousselGit/riverpod/issues/3718
|
||||
typedef ResponseErrorHandler = void Function(
|
||||
Response response, [
|
||||
Object? error,
|
||||
]);
|
||||
typedef ResponseErrorHandler =
|
||||
void Function(Response response, [Object? error]);
|
||||
|
||||
final _logger = Logger('api_provider');
|
||||
|
||||
|
|
@ -39,9 +37,7 @@ AudiobookshelfApi audiobookshelfApi(Ref ref, Uri? baseUrl) {
|
|||
// try to get the base url from app settings
|
||||
final apiSettings = ref.watch(apiSettingsProvider);
|
||||
baseUrl ??= apiSettings.activeServer?.serverUrl;
|
||||
return AudiobookshelfApi(
|
||||
baseUrl: makeBaseUrl(baseUrl.toString()),
|
||||
);
|
||||
return AudiobookshelfApi(baseUrl: makeBaseUrl(baseUrl.toString()));
|
||||
}
|
||||
|
||||
/// get the api instance for the authenticated user
|
||||
|
|
@ -68,9 +64,9 @@ FutureOr<bool> isServerAlive(Ref ref, String address) async {
|
|||
}
|
||||
|
||||
try {
|
||||
return await AudiobookshelfApi(baseUrl: makeBaseUrl(address))
|
||||
.server
|
||||
.ping() ??
|
||||
return await AudiobookshelfApi(
|
||||
baseUrl: makeBaseUrl(address),
|
||||
).server.ping() ??
|
||||
false;
|
||||
} catch (e) {
|
||||
return false;
|
||||
|
|
@ -86,8 +82,9 @@ FutureOr<ServerStatusResponse?> serverStatus(
|
|||
]) async {
|
||||
_logger.fine('fetching server status: ${baseUrl.obfuscate()}');
|
||||
final api = ref.watch(audiobookshelfApiProvider(baseUrl));
|
||||
final res =
|
||||
await api.server.status(responseErrorHandler: responseErrorHandler);
|
||||
final res = await api.server.status(
|
||||
responseErrorHandler: responseErrorHandler,
|
||||
);
|
||||
_logger.fine('server status: $res');
|
||||
return res;
|
||||
}
|
||||
|
|
@ -113,7 +110,9 @@ class PersonalizedView extends _$PersonalizedView {
|
|||
yield [];
|
||||
return;
|
||||
}
|
||||
ref.read(apiSettingsProvider.notifier).updateState(
|
||||
ref
|
||||
.read(apiSettingsProvider.notifier)
|
||||
.updateState(
|
||||
apiSettings.copyWith(activeLibraryId: login.userDefaultLibraryId),
|
||||
);
|
||||
yield [];
|
||||
|
|
@ -122,9 +121,8 @@ class PersonalizedView extends _$PersonalizedView {
|
|||
// try to find in cache
|
||||
// final cacheKey = 'personalizedView:${apiSettings.activeLibraryId}';
|
||||
final key = 'personalizedView:${apiSettings.activeLibraryId! + user.id}';
|
||||
final cachedRes = await apiResponseCacheManager.getFileFromMemory(
|
||||
key,
|
||||
) ??
|
||||
final cachedRes =
|
||||
await apiResponseCacheManager.getFileFromMemory(key) ??
|
||||
await apiResponseCacheManager.getFileFromCache(key);
|
||||
if (cachedRes != null) {
|
||||
_logger.fine('reading from cache: $cachedRes for key: $key');
|
||||
|
|
@ -143,8 +141,9 @@ class PersonalizedView extends _$PersonalizedView {
|
|||
|
||||
// ! exaggerated delay
|
||||
// await Future.delayed(const Duration(seconds: 2));
|
||||
final res = await api.libraries
|
||||
.getPersonalized(libraryId: apiSettings.activeLibraryId!);
|
||||
final res = await api.libraries.getPersonalized(
|
||||
libraryId: apiSettings.activeLibraryId!,
|
||||
);
|
||||
// debugPrint('personalizedView: ${res!.map((e) => e).toSet()}');
|
||||
// save to cache
|
||||
if (res != null) {
|
||||
|
|
@ -172,9 +171,7 @@ class PersonalizedView extends _$PersonalizedView {
|
|||
|
||||
/// fetch continue listening audiobooks
|
||||
@riverpod
|
||||
FutureOr<GetUserSessionsResponse> fetchContinueListening(
|
||||
Ref ref,
|
||||
) async {
|
||||
FutureOr<GetUserSessionsResponse> fetchContinueListening(Ref ref) async {
|
||||
final api = ref.watch(authenticatedApiProvider);
|
||||
final res = await api.me.getSessions();
|
||||
// debugPrint(
|
||||
|
|
@ -184,9 +181,7 @@ FutureOr<GetUserSessionsResponse> fetchContinueListening(
|
|||
}
|
||||
|
||||
@riverpod
|
||||
FutureOr<User> me(
|
||||
Ref ref,
|
||||
) async {
|
||||
FutureOr<User> me(Ref ref) async {
|
||||
final api = ref.watch(authenticatedApiProvider);
|
||||
final errorResponseHandler = ErrorResponseHandler();
|
||||
final res = await api.me.getUser(
|
||||
|
|
@ -202,10 +197,7 @@ FutureOr<User> me(
|
|||
}
|
||||
|
||||
@riverpod
|
||||
FutureOr<LoginResponse?> login(
|
||||
Ref ref, {
|
||||
AuthenticatedUser? user,
|
||||
}) async {
|
||||
FutureOr<LoginResponse?> login(Ref ref, {AuthenticatedUser? user}) async {
|
||||
if (user == null) {
|
||||
// try to get the user from settings
|
||||
final apiSettings = ref.watch(apiSettingsProvider);
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -19,7 +19,7 @@ final _logger = Logger('authenticated_users_provider');
|
|||
class AuthenticatedUsers extends _$AuthenticatedUsers {
|
||||
@override
|
||||
Set<model.AuthenticatedUser> build() {
|
||||
ref.listenSelf((_, __) {
|
||||
listenSelf((_, __) {
|
||||
writeStateToBox();
|
||||
});
|
||||
// get the app settings
|
||||
|
|
@ -35,9 +35,7 @@ class AuthenticatedUsers extends _$AuthenticatedUsers {
|
|||
Set<model.AuthenticatedUser> readFromBoxOrCreate() {
|
||||
if (_box.isNotEmpty) {
|
||||
final foundData = _box.getRange(0, _box.length);
|
||||
_logger.fine(
|
||||
'found users in box: ${foundData.obfuscate()}',
|
||||
);
|
||||
_logger.fine('found users in box: ${foundData.obfuscate()}');
|
||||
return foundData.toSet();
|
||||
} else {
|
||||
_logger.fine('no settings found in box');
|
||||
|
|
@ -59,11 +57,9 @@ class AuthenticatedUsers extends _$AuthenticatedUsers {
|
|||
ref.invalidateSelf();
|
||||
if (setActive) {
|
||||
final apiSettings = ref.read(apiSettingsProvider);
|
||||
ref.read(apiSettingsProvider.notifier).updateState(
|
||||
apiSettings.copyWith(
|
||||
activeUser: user,
|
||||
),
|
||||
);
|
||||
ref
|
||||
.read(apiSettingsProvider.notifier)
|
||||
.updateState(apiSettings.copyWith(activeUser: user));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -86,11 +82,9 @@ class AuthenticatedUsers extends _$AuthenticatedUsers {
|
|||
// replace the active user with the first user in the list
|
||||
// or null if there are no users left
|
||||
final newActiveUser = state.isNotEmpty ? state.first : null;
|
||||
ref.read(apiSettingsProvider.notifier).updateState(
|
||||
apiSettings.copyWith(
|
||||
activeUser: newActiveUser,
|
||||
),
|
||||
);
|
||||
ref
|
||||
.read(apiSettingsProvider.notifier)
|
||||
.updateState(apiSettings.copyWith(activeUser: newActiveUser));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,25 +6,70 @@ part of 'authenticated_users_provider.dart';
|
|||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$authenticatedUsersHash() =>
|
||||
r'5fdd472f62fc3b73ff8417cdce9f02e86c33d00f';
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
/// provides with a set of authenticated users
|
||||
|
||||
@ProviderFor(AuthenticatedUsers)
|
||||
final authenticatedUsersProvider = AuthenticatedUsersProvider._();
|
||||
|
||||
/// provides with a set of authenticated users
|
||||
///
|
||||
/// Copied from [AuthenticatedUsers].
|
||||
@ProviderFor(AuthenticatedUsers)
|
||||
final authenticatedUsersProvider = AutoDisposeNotifierProvider<
|
||||
AuthenticatedUsers, Set<model.AuthenticatedUser>>.internal(
|
||||
AuthenticatedUsers.new,
|
||||
name: r'authenticatedUsersProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$authenticatedUsersHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
final class AuthenticatedUsersProvider
|
||||
extends
|
||||
$NotifierProvider<AuthenticatedUsers, Set<model.AuthenticatedUser>> {
|
||||
/// provides with a set of authenticated users
|
||||
AuthenticatedUsersProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
retry: null,
|
||||
name: r'authenticatedUsersProvider',
|
||||
isAutoDispose: true,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
typedef _$AuthenticatedUsers
|
||||
= AutoDisposeNotifier<Set<model.AuthenticatedUser>>;
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$authenticatedUsersHash();
|
||||
|
||||
@$internal
|
||||
@override
|
||||
AuthenticatedUsers create() => AuthenticatedUsers();
|
||||
|
||||
/// {@macro riverpod.override_with_value}
|
||||
Override overrideWithValue(Set<model.AuthenticatedUser> value) {
|
||||
return $ProviderOverride(
|
||||
origin: this,
|
||||
providerOverride: $SyncValueProvider<Set<model.AuthenticatedUser>>(value),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
String _$authenticatedUsersHash() =>
|
||||
r'c5e82cc70ffc31a0d315e3db9e07a141c583471e';
|
||||
|
||||
/// provides with a set of authenticated users
|
||||
|
||||
abstract class _$AuthenticatedUsers
|
||||
extends $Notifier<Set<model.AuthenticatedUser>> {
|
||||
Set<model.AuthenticatedUser> build();
|
||||
@$mustCallSuper
|
||||
@override
|
||||
void runBuild() {
|
||||
final ref =
|
||||
this.ref
|
||||
as $Ref<Set<model.AuthenticatedUser>, Set<model.AuthenticatedUser>>;
|
||||
final element =
|
||||
ref.element
|
||||
as $ClassProviderElement<
|
||||
AnyNotifier<
|
||||
Set<model.AuthenticatedUser>,
|
||||
Set<model.AuthenticatedUser>
|
||||
>,
|
||||
Set<model.AuthenticatedUser>,
|
||||
Object?,
|
||||
Object?
|
||||
>;
|
||||
element.handleCreate(ref, build);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,7 +27,8 @@ class CoverImage extends _$CoverImage {
|
|||
// await Future.delayed(const Duration(seconds: 2));
|
||||
|
||||
// try to get the image from the cache
|
||||
final file = await imageCacheManager.getFileFromMemory(itemId) ??
|
||||
final file =
|
||||
await imageCacheManager.getFileFromMemory(itemId) ??
|
||||
await imageCacheManager.getFileFromCache(itemId);
|
||||
|
||||
if (file != null) {
|
||||
|
|
@ -44,9 +45,7 @@ class CoverImage extends _$CoverImage {
|
|||
);
|
||||
return;
|
||||
} else {
|
||||
_logger.fine(
|
||||
'cover image stale for $itemId, fetching from the server',
|
||||
);
|
||||
_logger.fine('cover image stale for $itemId, fetching from the server');
|
||||
}
|
||||
} else {
|
||||
_logger.fine('cover image not found in cache for $itemId');
|
||||
|
|
|
|||
|
|
@ -6,169 +6,94 @@ part of 'image_provider.dart';
|
|||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$coverImageHash() => r'89cc4783cbc76bb41beae34384d92fb277135c75';
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
_SystemHash._();
|
||||
|
||||
static int combine(int hash, int value) {
|
||||
// ignore: parameter_assignments
|
||||
hash = 0x1fffffff & (hash + value);
|
||||
// ignore: parameter_assignments
|
||||
hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
|
||||
return hash ^ (hash >> 6);
|
||||
}
|
||||
|
||||
static int finish(int hash) {
|
||||
// ignore: parameter_assignments
|
||||
hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
|
||||
// ignore: parameter_assignments
|
||||
hash = hash ^ (hash >> 11);
|
||||
return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _$CoverImage extends BuildlessStreamNotifier<Uint8List> {
|
||||
late final String itemId;
|
||||
|
||||
Stream<Uint8List> build(
|
||||
String itemId,
|
||||
);
|
||||
}
|
||||
|
||||
/// See also [CoverImage].
|
||||
@ProviderFor(CoverImage)
|
||||
const coverImageProvider = CoverImageFamily();
|
||||
final coverImageProvider = CoverImageFamily._();
|
||||
|
||||
/// See also [CoverImage].
|
||||
class CoverImageFamily extends Family<AsyncValue<Uint8List>> {
|
||||
/// See also [CoverImage].
|
||||
const CoverImageFamily();
|
||||
final class CoverImageProvider
|
||||
extends $StreamNotifierProvider<CoverImage, Uint8List> {
|
||||
CoverImageProvider._({
|
||||
required CoverImageFamily super.from,
|
||||
required String super.argument,
|
||||
}) : super(
|
||||
retry: null,
|
||||
name: r'coverImageProvider',
|
||||
isAutoDispose: false,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
/// See also [CoverImage].
|
||||
CoverImageProvider call(
|
||||
String itemId,
|
||||
) {
|
||||
return CoverImageProvider(
|
||||
itemId,
|
||||
);
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$coverImageHash();
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return r'coverImageProvider'
|
||||
''
|
||||
'($argument)';
|
||||
}
|
||||
|
||||
@$internal
|
||||
@override
|
||||
CoverImageProvider getProviderOverride(
|
||||
covariant CoverImageProvider provider,
|
||||
) {
|
||||
return call(
|
||||
provider.itemId,
|
||||
);
|
||||
}
|
||||
|
||||
static const Iterable<ProviderOrFamily>? _dependencies = null;
|
||||
|
||||
@override
|
||||
Iterable<ProviderOrFamily>? get dependencies => _dependencies;
|
||||
|
||||
static const Iterable<ProviderOrFamily>? _allTransitiveDependencies = null;
|
||||
|
||||
@override
|
||||
Iterable<ProviderOrFamily>? get allTransitiveDependencies =>
|
||||
_allTransitiveDependencies;
|
||||
|
||||
@override
|
||||
String? get name => r'coverImageProvider';
|
||||
}
|
||||
|
||||
/// See also [CoverImage].
|
||||
class CoverImageProvider
|
||||
extends StreamNotifierProviderImpl<CoverImage, Uint8List> {
|
||||
/// See also [CoverImage].
|
||||
CoverImageProvider(
|
||||
String itemId,
|
||||
) : this._internal(
|
||||
() => CoverImage()..itemId = itemId,
|
||||
from: coverImageProvider,
|
||||
name: r'coverImageProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$coverImageHash,
|
||||
dependencies: CoverImageFamily._dependencies,
|
||||
allTransitiveDependencies:
|
||||
CoverImageFamily._allTransitiveDependencies,
|
||||
itemId: itemId,
|
||||
);
|
||||
|
||||
CoverImageProvider._internal(
|
||||
super._createNotifier, {
|
||||
required super.name,
|
||||
required super.dependencies,
|
||||
required super.allTransitiveDependencies,
|
||||
required super.debugGetCreateSourceHash,
|
||||
required super.from,
|
||||
required this.itemId,
|
||||
}) : super.internal();
|
||||
|
||||
final String itemId;
|
||||
|
||||
@override
|
||||
Stream<Uint8List> runNotifierBuild(
|
||||
covariant CoverImage notifier,
|
||||
) {
|
||||
return notifier.build(
|
||||
itemId,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Override overrideWith(CoverImage Function() create) {
|
||||
return ProviderOverride(
|
||||
origin: this,
|
||||
override: CoverImageProvider._internal(
|
||||
() => create()..itemId = itemId,
|
||||
from: from,
|
||||
name: null,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
debugGetCreateSourceHash: null,
|
||||
itemId: itemId,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
StreamNotifierProviderElement<CoverImage, Uint8List> createElement() {
|
||||
return _CoverImageProviderElement(this);
|
||||
}
|
||||
CoverImage create() => CoverImage();
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is CoverImageProvider && other.itemId == itemId;
|
||||
return other is CoverImageProvider && other.argument == argument;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
||||
hash = _SystemHash.combine(hash, itemId.hashCode);
|
||||
|
||||
return _SystemHash.finish(hash);
|
||||
return argument.hashCode;
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||
// ignore: unused_element
|
||||
mixin CoverImageRef on StreamNotifierProviderRef<Uint8List> {
|
||||
/// The parameter `itemId` of this provider.
|
||||
String get itemId;
|
||||
}
|
||||
String _$coverImageHash() => r'89cc4783cbc76bb41beae34384d92fb277135c75';
|
||||
|
||||
class _CoverImageProviderElement
|
||||
extends StreamNotifierProviderElement<CoverImage, Uint8List>
|
||||
with CoverImageRef {
|
||||
_CoverImageProviderElement(super.provider);
|
||||
final class CoverImageFamily extends $Family
|
||||
with
|
||||
$ClassFamilyOverride<
|
||||
CoverImage,
|
||||
AsyncValue<Uint8List>,
|
||||
Uint8List,
|
||||
Stream<Uint8List>,
|
||||
String
|
||||
> {
|
||||
CoverImageFamily._()
|
||||
: super(
|
||||
retry: null,
|
||||
name: r'coverImageProvider',
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
isAutoDispose: false,
|
||||
);
|
||||
|
||||
CoverImageProvider call(String itemId) =>
|
||||
CoverImageProvider._(argument: itemId, from: this);
|
||||
|
||||
@override
|
||||
String get itemId => (origin as CoverImageProvider).itemId;
|
||||
String toString() => r'coverImageProvider';
|
||||
}
|
||||
|
||||
abstract class _$CoverImage extends $StreamNotifier<Uint8List> {
|
||||
late final _$args = ref.$arg as String;
|
||||
String get itemId => _$args;
|
||||
|
||||
Stream<Uint8List> build(String itemId);
|
||||
@$mustCallSuper
|
||||
@override
|
||||
void runBuild() {
|
||||
final ref = this.ref as $Ref<AsyncValue<Uint8List>, Uint8List>;
|
||||
final element =
|
||||
ref.element
|
||||
as $ClassProviderElement<
|
||||
AnyNotifier<AsyncValue<Uint8List>, Uint8List>,
|
||||
AsyncValue<Uint8List>,
|
||||
Object?,
|
||||
Object?
|
||||
>;
|
||||
element.handleCreate(ref, () => build(_$args));
|
||||
}
|
||||
}
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package
|
||||
|
|
|
|||
|
|
@ -26,7 +26,8 @@ class LibraryItem extends _$LibraryItem {
|
|||
|
||||
// look for the item in the cache
|
||||
final key = CacheKey.libraryItem(id);
|
||||
final cachedFile = await apiResponseCacheManager.getFileFromMemory(key) ??
|
||||
final cachedFile =
|
||||
await apiResponseCacheManager.getFileFromMemory(key) ??
|
||||
await apiResponseCacheManager.getFileFromCache(key);
|
||||
if (cachedFile != null) {
|
||||
_logger.fine(
|
||||
|
|
|
|||
|
|
@ -6,184 +6,112 @@ part of 'library_item_provider.dart';
|
|||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$libraryItemHash() => r'a3cfa7f912e9498a70b5782899018b6964d6445c';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
_SystemHash._();
|
||||
|
||||
static int combine(int hash, int value) {
|
||||
// ignore: parameter_assignments
|
||||
hash = 0x1fffffff & (hash + value);
|
||||
// ignore: parameter_assignments
|
||||
hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
|
||||
return hash ^ (hash >> 6);
|
||||
}
|
||||
|
||||
static int finish(int hash) {
|
||||
// ignore: parameter_assignments
|
||||
hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
|
||||
// ignore: parameter_assignments
|
||||
hash = hash ^ (hash >> 11);
|
||||
return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _$LibraryItem
|
||||
extends BuildlessStreamNotifier<shelfsdk.LibraryItemExpanded> {
|
||||
late final String id;
|
||||
|
||||
Stream<shelfsdk.LibraryItemExpanded> build(
|
||||
String id,
|
||||
);
|
||||
}
|
||||
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
/// provides the library item for the given id
|
||||
///
|
||||
/// Copied from [LibraryItem].
|
||||
|
||||
@ProviderFor(LibraryItem)
|
||||
const libraryItemProvider = LibraryItemFamily();
|
||||
final libraryItemProvider = LibraryItemFamily._();
|
||||
|
||||
/// provides the library item for the given id
|
||||
///
|
||||
/// Copied from [LibraryItem].
|
||||
class LibraryItemFamily
|
||||
extends Family<AsyncValue<shelfsdk.LibraryItemExpanded>> {
|
||||
final class LibraryItemProvider
|
||||
extends $StreamNotifierProvider<LibraryItem, shelfsdk.LibraryItemExpanded> {
|
||||
/// provides the library item for the given id
|
||||
///
|
||||
/// Copied from [LibraryItem].
|
||||
const LibraryItemFamily();
|
||||
LibraryItemProvider._({
|
||||
required LibraryItemFamily super.from,
|
||||
required String super.argument,
|
||||
}) : super(
|
||||
retry: null,
|
||||
name: r'libraryItemProvider',
|
||||
isAutoDispose: false,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
/// provides the library item for the given id
|
||||
///
|
||||
/// Copied from [LibraryItem].
|
||||
LibraryItemProvider call(
|
||||
String id,
|
||||
) {
|
||||
return LibraryItemProvider(
|
||||
id,
|
||||
);
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$libraryItemHash();
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return r'libraryItemProvider'
|
||||
''
|
||||
'($argument)';
|
||||
}
|
||||
|
||||
@$internal
|
||||
@override
|
||||
LibraryItemProvider getProviderOverride(
|
||||
covariant LibraryItemProvider provider,
|
||||
) {
|
||||
return call(
|
||||
provider.id,
|
||||
);
|
||||
}
|
||||
|
||||
static const Iterable<ProviderOrFamily>? _dependencies = null;
|
||||
|
||||
@override
|
||||
Iterable<ProviderOrFamily>? get dependencies => _dependencies;
|
||||
|
||||
static const Iterable<ProviderOrFamily>? _allTransitiveDependencies = null;
|
||||
|
||||
@override
|
||||
Iterable<ProviderOrFamily>? get allTransitiveDependencies =>
|
||||
_allTransitiveDependencies;
|
||||
|
||||
@override
|
||||
String? get name => r'libraryItemProvider';
|
||||
}
|
||||
|
||||
/// provides the library item for the given id
|
||||
///
|
||||
/// Copied from [LibraryItem].
|
||||
class LibraryItemProvider extends StreamNotifierProviderImpl<LibraryItem,
|
||||
shelfsdk.LibraryItemExpanded> {
|
||||
/// provides the library item for the given id
|
||||
///
|
||||
/// Copied from [LibraryItem].
|
||||
LibraryItemProvider(
|
||||
String id,
|
||||
) : this._internal(
|
||||
() => LibraryItem()..id = id,
|
||||
from: libraryItemProvider,
|
||||
name: r'libraryItemProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$libraryItemHash,
|
||||
dependencies: LibraryItemFamily._dependencies,
|
||||
allTransitiveDependencies:
|
||||
LibraryItemFamily._allTransitiveDependencies,
|
||||
id: id,
|
||||
);
|
||||
|
||||
LibraryItemProvider._internal(
|
||||
super._createNotifier, {
|
||||
required super.name,
|
||||
required super.dependencies,
|
||||
required super.allTransitiveDependencies,
|
||||
required super.debugGetCreateSourceHash,
|
||||
required super.from,
|
||||
required this.id,
|
||||
}) : super.internal();
|
||||
|
||||
final String id;
|
||||
|
||||
@override
|
||||
Stream<shelfsdk.LibraryItemExpanded> runNotifierBuild(
|
||||
covariant LibraryItem notifier,
|
||||
) {
|
||||
return notifier.build(
|
||||
id,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Override overrideWith(LibraryItem Function() create) {
|
||||
return ProviderOverride(
|
||||
origin: this,
|
||||
override: LibraryItemProvider._internal(
|
||||
() => create()..id = id,
|
||||
from: from,
|
||||
name: null,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
debugGetCreateSourceHash: null,
|
||||
id: id,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
StreamNotifierProviderElement<LibraryItem, shelfsdk.LibraryItemExpanded>
|
||||
createElement() {
|
||||
return _LibraryItemProviderElement(this);
|
||||
}
|
||||
LibraryItem create() => LibraryItem();
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is LibraryItemProvider && other.id == id;
|
||||
return other is LibraryItemProvider && other.argument == argument;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
||||
hash = _SystemHash.combine(hash, id.hashCode);
|
||||
|
||||
return _SystemHash.finish(hash);
|
||||
return argument.hashCode;
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||
// ignore: unused_element
|
||||
mixin LibraryItemRef
|
||||
on StreamNotifierProviderRef<shelfsdk.LibraryItemExpanded> {
|
||||
/// The parameter `id` of this provider.
|
||||
String get id;
|
||||
}
|
||||
String _$libraryItemHash() => r'a3cfa7f912e9498a70b5782899018b6964d6445c';
|
||||
|
||||
class _LibraryItemProviderElement extends StreamNotifierProviderElement<
|
||||
LibraryItem, shelfsdk.LibraryItemExpanded> with LibraryItemRef {
|
||||
_LibraryItemProviderElement(super.provider);
|
||||
/// provides the library item for the given id
|
||||
|
||||
final class LibraryItemFamily extends $Family
|
||||
with
|
||||
$ClassFamilyOverride<
|
||||
LibraryItem,
|
||||
AsyncValue<shelfsdk.LibraryItemExpanded>,
|
||||
shelfsdk.LibraryItemExpanded,
|
||||
Stream<shelfsdk.LibraryItemExpanded>,
|
||||
String
|
||||
> {
|
||||
LibraryItemFamily._()
|
||||
: super(
|
||||
retry: null,
|
||||
name: r'libraryItemProvider',
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
isAutoDispose: false,
|
||||
);
|
||||
|
||||
/// provides the library item for the given id
|
||||
|
||||
LibraryItemProvider call(String id) =>
|
||||
LibraryItemProvider._(argument: id, from: this);
|
||||
|
||||
@override
|
||||
String get id => (origin as LibraryItemProvider).id;
|
||||
String toString() => r'libraryItemProvider';
|
||||
}
|
||||
|
||||
/// provides the library item for the given id
|
||||
|
||||
abstract class _$LibraryItem
|
||||
extends $StreamNotifier<shelfsdk.LibraryItemExpanded> {
|
||||
late final _$args = ref.$arg as String;
|
||||
String get id => _$args;
|
||||
|
||||
Stream<shelfsdk.LibraryItemExpanded> build(String id);
|
||||
@$mustCallSuper
|
||||
@override
|
||||
void runBuild() {
|
||||
final ref =
|
||||
this.ref
|
||||
as $Ref<
|
||||
AsyncValue<shelfsdk.LibraryItemExpanded>,
|
||||
shelfsdk.LibraryItemExpanded
|
||||
>;
|
||||
final element =
|
||||
ref.element
|
||||
as $ClassProviderElement<
|
||||
AnyNotifier<
|
||||
AsyncValue<shelfsdk.LibraryItemExpanded>,
|
||||
shelfsdk.LibraryItemExpanded
|
||||
>,
|
||||
AsyncValue<shelfsdk.LibraryItemExpanded>,
|
||||
Object?,
|
||||
Object?
|
||||
>;
|
||||
element.handleCreate(ref, () => build(_$args));
|
||||
}
|
||||
}
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import 'package:hooks_riverpod/hooks_riverpod.dart' show Ref;
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart'
|
||||
show Ref, ProviderListenableSelect;
|
||||
import 'package:logging/logging.dart' show Logger;
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
|
||||
|
|
@ -32,8 +33,9 @@ Future<Library?> library(Ref ref, String id) async {
|
|||
|
||||
@riverpod
|
||||
Future<Library?> currentLibrary(Ref ref) async {
|
||||
final libraryId =
|
||||
ref.watch(apiSettingsProvider.select((s) => s.activeLibraryId));
|
||||
final libraryId = ref.watch(
|
||||
apiSettingsProvider.select((s) => s.activeLibraryId),
|
||||
);
|
||||
if (libraryId == null) {
|
||||
_logger.warning('No active library id found');
|
||||
return null;
|
||||
|
|
|
|||
|
|
@ -6,187 +6,153 @@ part of 'library_provider.dart';
|
|||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$libraryHash() => r'f8a34100acb58f02fa958c71a629577bf815710e';
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
_SystemHash._();
|
||||
|
||||
static int combine(int hash, int value) {
|
||||
// ignore: parameter_assignments
|
||||
hash = 0x1fffffff & (hash + value);
|
||||
// ignore: parameter_assignments
|
||||
hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
|
||||
return hash ^ (hash >> 6);
|
||||
}
|
||||
|
||||
static int finish(int hash) {
|
||||
// ignore: parameter_assignments
|
||||
hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
|
||||
// ignore: parameter_assignments
|
||||
hash = hash ^ (hash >> 11);
|
||||
return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
|
||||
}
|
||||
}
|
||||
|
||||
/// See also [library].
|
||||
@ProviderFor(library)
|
||||
const libraryProvider = LibraryFamily();
|
||||
final libraryProvider = LibraryFamily._();
|
||||
|
||||
/// See also [library].
|
||||
class LibraryFamily extends Family<AsyncValue<Library?>> {
|
||||
/// See also [library].
|
||||
const LibraryFamily();
|
||||
final class LibraryProvider
|
||||
extends
|
||||
$FunctionalProvider<AsyncValue<Library?>, Library?, FutureOr<Library?>>
|
||||
with $FutureModifier<Library?>, $FutureProvider<Library?> {
|
||||
LibraryProvider._({
|
||||
required LibraryFamily super.from,
|
||||
required String super.argument,
|
||||
}) : super(
|
||||
retry: null,
|
||||
name: r'libraryProvider',
|
||||
isAutoDispose: true,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
/// See also [library].
|
||||
LibraryProvider call(
|
||||
String id,
|
||||
) {
|
||||
return LibraryProvider(
|
||||
id,
|
||||
);
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$libraryHash();
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return r'libraryProvider'
|
||||
''
|
||||
'($argument)';
|
||||
}
|
||||
|
||||
@$internal
|
||||
@override
|
||||
LibraryProvider getProviderOverride(
|
||||
covariant LibraryProvider provider,
|
||||
) {
|
||||
return call(
|
||||
provider.id,
|
||||
);
|
||||
}
|
||||
|
||||
static const Iterable<ProviderOrFamily>? _dependencies = null;
|
||||
$FutureProviderElement<Library?> $createElement($ProviderPointer pointer) =>
|
||||
$FutureProviderElement(pointer);
|
||||
|
||||
@override
|
||||
Iterable<ProviderOrFamily>? get dependencies => _dependencies;
|
||||
|
||||
static const Iterable<ProviderOrFamily>? _allTransitiveDependencies = null;
|
||||
|
||||
@override
|
||||
Iterable<ProviderOrFamily>? get allTransitiveDependencies =>
|
||||
_allTransitiveDependencies;
|
||||
|
||||
@override
|
||||
String? get name => r'libraryProvider';
|
||||
}
|
||||
|
||||
/// See also [library].
|
||||
class LibraryProvider extends AutoDisposeFutureProvider<Library?> {
|
||||
/// See also [library].
|
||||
LibraryProvider(
|
||||
String id,
|
||||
) : this._internal(
|
||||
(ref) => library(
|
||||
ref as LibraryRef,
|
||||
id,
|
||||
),
|
||||
from: libraryProvider,
|
||||
name: r'libraryProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$libraryHash,
|
||||
dependencies: LibraryFamily._dependencies,
|
||||
allTransitiveDependencies: LibraryFamily._allTransitiveDependencies,
|
||||
id: id,
|
||||
);
|
||||
|
||||
LibraryProvider._internal(
|
||||
super._createNotifier, {
|
||||
required super.name,
|
||||
required super.dependencies,
|
||||
required super.allTransitiveDependencies,
|
||||
required super.debugGetCreateSourceHash,
|
||||
required super.from,
|
||||
required this.id,
|
||||
}) : super.internal();
|
||||
|
||||
final String id;
|
||||
|
||||
@override
|
||||
Override overrideWith(
|
||||
FutureOr<Library?> Function(LibraryRef provider) create,
|
||||
) {
|
||||
return ProviderOverride(
|
||||
origin: this,
|
||||
override: LibraryProvider._internal(
|
||||
(ref) => create(ref as LibraryRef),
|
||||
from: from,
|
||||
name: null,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
debugGetCreateSourceHash: null,
|
||||
id: id,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
AutoDisposeFutureProviderElement<Library?> createElement() {
|
||||
return _LibraryProviderElement(this);
|
||||
FutureOr<Library?> create(Ref ref) {
|
||||
final argument = this.argument as String;
|
||||
return library(ref, argument);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is LibraryProvider && other.id == id;
|
||||
return other is LibraryProvider && other.argument == argument;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
||||
hash = _SystemHash.combine(hash, id.hashCode);
|
||||
|
||||
return _SystemHash.finish(hash);
|
||||
return argument.hashCode;
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||
// ignore: unused_element
|
||||
mixin LibraryRef on AutoDisposeFutureProviderRef<Library?> {
|
||||
/// The parameter `id` of this provider.
|
||||
String get id;
|
||||
}
|
||||
String _$libraryHash() => r'f8a34100acb58f02fa958c71a629577bf815710e';
|
||||
|
||||
class _LibraryProviderElement extends AutoDisposeFutureProviderElement<Library?>
|
||||
with LibraryRef {
|
||||
_LibraryProviderElement(super.provider);
|
||||
final class LibraryFamily extends $Family
|
||||
with $FunctionalFamilyOverride<FutureOr<Library?>, String> {
|
||||
LibraryFamily._()
|
||||
: super(
|
||||
retry: null,
|
||||
name: r'libraryProvider',
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
isAutoDispose: true,
|
||||
);
|
||||
|
||||
LibraryProvider call(String id) =>
|
||||
LibraryProvider._(argument: id, from: this);
|
||||
|
||||
@override
|
||||
String get id => (origin as LibraryProvider).id;
|
||||
String toString() => r'libraryProvider';
|
||||
}
|
||||
|
||||
@ProviderFor(currentLibrary)
|
||||
final currentLibraryProvider = CurrentLibraryProvider._();
|
||||
|
||||
final class CurrentLibraryProvider
|
||||
extends
|
||||
$FunctionalProvider<AsyncValue<Library?>, Library?, FutureOr<Library?>>
|
||||
with $FutureModifier<Library?>, $FutureProvider<Library?> {
|
||||
CurrentLibraryProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
retry: null,
|
||||
name: r'currentLibraryProvider',
|
||||
isAutoDispose: true,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$currentLibraryHash();
|
||||
|
||||
@$internal
|
||||
@override
|
||||
$FutureProviderElement<Library?> $createElement($ProviderPointer pointer) =>
|
||||
$FutureProviderElement(pointer);
|
||||
|
||||
@override
|
||||
FutureOr<Library?> create(Ref ref) {
|
||||
return currentLibrary(ref);
|
||||
}
|
||||
}
|
||||
|
||||
String _$currentLibraryHash() => r'658498a531e04a01e2b3915a3319101285601118';
|
||||
|
||||
/// See also [currentLibrary].
|
||||
@ProviderFor(currentLibrary)
|
||||
final currentLibraryProvider = AutoDisposeFutureProvider<Library?>.internal(
|
||||
currentLibrary,
|
||||
name: r'currentLibraryProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$currentLibraryHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
@ProviderFor(Libraries)
|
||||
final librariesProvider = LibrariesProvider._();
|
||||
|
||||
final class LibrariesProvider
|
||||
extends $AsyncNotifierProvider<Libraries, List<Library>> {
|
||||
LibrariesProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
retry: null,
|
||||
name: r'librariesProvider',
|
||||
isAutoDispose: true,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$librariesHash();
|
||||
|
||||
@$internal
|
||||
@override
|
||||
Libraries create() => Libraries();
|
||||
}
|
||||
|
||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||
// ignore: unused_element
|
||||
typedef CurrentLibraryRef = AutoDisposeFutureProviderRef<Library?>;
|
||||
String _$librariesHash() => r'95ebd4d1ac0cc2acf7617dc22895eff0ca30600f';
|
||||
|
||||
/// See also [Libraries].
|
||||
@ProviderFor(Libraries)
|
||||
final librariesProvider =
|
||||
AutoDisposeAsyncNotifierProvider<Libraries, List<Library>>.internal(
|
||||
Libraries.new,
|
||||
name: r'librariesProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product') ? null : _$librariesHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
typedef _$Libraries = AutoDisposeAsyncNotifier<List<Library>>;
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package
|
||||
abstract class _$Libraries extends $AsyncNotifier<List<Library>> {
|
||||
FutureOr<List<Library>> build();
|
||||
@$mustCallSuper
|
||||
@override
|
||||
void runBuild() {
|
||||
final ref = this.ref as $Ref<AsyncValue<List<Library>>, List<Library>>;
|
||||
final element =
|
||||
ref.element
|
||||
as $ClassProviderElement<
|
||||
AnyNotifier<AsyncValue<List<Library>>, List<Library>>,
|
||||
AsyncValue<List<Library>>,
|
||||
Object?,
|
||||
Object?
|
||||
>;
|
||||
element.handleCreate(ref, build);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ class ServerAlreadyExistsException implements Exception {
|
|||
class AudiobookShelfServer extends _$AudiobookShelfServer {
|
||||
@override
|
||||
Set<model.AudiobookShelfServer> build() {
|
||||
ref.listenSelf((_, __) {
|
||||
listenSelf((_, __) {
|
||||
writeStateToBox();
|
||||
});
|
||||
// get the app settings
|
||||
|
|
@ -80,11 +80,9 @@ class AudiobookShelfServer extends _$AudiobookShelfServer {
|
|||
// remove the server from the active server
|
||||
final apiSettings = ref.read(apiSettingsProvider);
|
||||
if (apiSettings.activeServer == server) {
|
||||
ref.read(apiSettingsProvider.notifier).updateState(
|
||||
apiSettings.copyWith(
|
||||
activeServer: null,
|
||||
),
|
||||
);
|
||||
ref
|
||||
.read(apiSettingsProvider.notifier)
|
||||
.updateState(apiSettings.copyWith(activeServer: null));
|
||||
}
|
||||
// remove the users of this server
|
||||
if (removeUsers) {
|
||||
|
|
|
|||
|
|
@ -6,25 +6,78 @@ part of 'server_provider.dart';
|
|||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$audiobookShelfServerHash() =>
|
||||
r'31a96b431221965cd586aad670a32ca901539e41';
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
/// provides with a set of servers added by the user
|
||||
|
||||
@ProviderFor(AudiobookShelfServer)
|
||||
final audiobookShelfServerProvider = AudiobookShelfServerProvider._();
|
||||
|
||||
/// provides with a set of servers added by the user
|
||||
///
|
||||
/// Copied from [AudiobookShelfServer].
|
||||
@ProviderFor(AudiobookShelfServer)
|
||||
final audiobookShelfServerProvider = AutoDisposeNotifierProvider<
|
||||
AudiobookShelfServer, Set<model.AudiobookShelfServer>>.internal(
|
||||
AudiobookShelfServer.new,
|
||||
name: r'audiobookShelfServerProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$audiobookShelfServerHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
final class AudiobookShelfServerProvider
|
||||
extends
|
||||
$NotifierProvider<
|
||||
AudiobookShelfServer,
|
||||
Set<model.AudiobookShelfServer>
|
||||
> {
|
||||
/// provides with a set of servers added by the user
|
||||
AudiobookShelfServerProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
retry: null,
|
||||
name: r'audiobookShelfServerProvider',
|
||||
isAutoDispose: true,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
typedef _$AudiobookShelfServer
|
||||
= AutoDisposeNotifier<Set<model.AudiobookShelfServer>>;
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$audiobookShelfServerHash();
|
||||
|
||||
@$internal
|
||||
@override
|
||||
AudiobookShelfServer create() => AudiobookShelfServer();
|
||||
|
||||
/// {@macro riverpod.override_with_value}
|
||||
Override overrideWithValue(Set<model.AudiobookShelfServer> value) {
|
||||
return $ProviderOverride(
|
||||
origin: this,
|
||||
providerOverride: $SyncValueProvider<Set<model.AudiobookShelfServer>>(
|
||||
value,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
String _$audiobookShelfServerHash() =>
|
||||
r'144817dcb3704b80c5b60763167fcf932f00c29c';
|
||||
|
||||
/// provides with a set of servers added by the user
|
||||
|
||||
abstract class _$AudiobookShelfServer
|
||||
extends $Notifier<Set<model.AudiobookShelfServer>> {
|
||||
Set<model.AudiobookShelfServer> build();
|
||||
@$mustCallSuper
|
||||
@override
|
||||
void runBuild() {
|
||||
final ref =
|
||||
this.ref
|
||||
as $Ref<
|
||||
Set<model.AudiobookShelfServer>,
|
||||
Set<model.AudiobookShelfServer>
|
||||
>;
|
||||
final element =
|
||||
ref.element
|
||||
as $ClassProviderElement<
|
||||
AnyNotifier<
|
||||
Set<model.AudiobookShelfServer>,
|
||||
Set<model.AudiobookShelfServer>
|
||||
>,
|
||||
Set<model.AudiobookShelfServer>,
|
||||
Object?,
|
||||
Object?
|
||||
>;
|
||||
element.handleCreate(ref, build);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import 'package:flutter/foundation.dart' show immutable;
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:hive_plus_secure/hive_plus_secure.dart';
|
||||
import 'package:vaani/features/per_book_settings/models/book_settings.dart';
|
||||
import 'package:vaani/settings/models/models.dart';
|
||||
|
||||
|
|
@ -14,14 +14,17 @@ class AvailableHiveBoxes {
|
|||
static final apiSettingsBox = Hive.box<ApiSettings>(name: 'apiSettings');
|
||||
|
||||
/// stores the a list of [AudiobookShelfServer]
|
||||
static final serverBox =
|
||||
Hive.box<AudiobookShelfServer>(name: 'audiobookShelfServer');
|
||||
static final serverBox = Hive.box<AudiobookShelfServer>(
|
||||
name: 'audiobookShelfServer',
|
||||
);
|
||||
|
||||
/// stores the a list of [AuthenticatedUser]
|
||||
static final authenticatedUserBox =
|
||||
Hive.box<AuthenticatedUser>(name: 'authenticatedUser');
|
||||
static final authenticatedUserBox = Hive.box<AuthenticatedUser>(
|
||||
name: 'authenticatedUser',
|
||||
);
|
||||
|
||||
/// stores the a list of [BookSettings]
|
||||
static final individualBookSettingsBox =
|
||||
Hive.box<BookSettings>(name: 'bookSettings');
|
||||
static final individualBookSettingsBox = Hive.box<BookSettings>(
|
||||
name: 'bookSettings',
|
||||
);
|
||||
}
|
||||
|
|
|
|||
66
lib/db/cache/schemas/image.dart
vendored
66
lib/db/cache/schemas/image.dart
vendored
|
|
@ -1,39 +1,39 @@
|
|||
import 'package:isar/isar.dart';
|
||||
// import 'package:isar/isar.dart';
|
||||
|
||||
part 'image.g.dart';
|
||||
// part 'image.g.dart';
|
||||
|
||||
/// Represents a cover image for a library item
|
||||
///
|
||||
/// stores 2 paths, one is thumbnail and the other is the full size image
|
||||
/// both are optional
|
||||
/// also stores last fetched date for the image
|
||||
/// Id is passed as a parameter to the collection annotation (the lib_item_id)
|
||||
/// also index the id
|
||||
/// This is because the image is a part of the library item and the library item
|
||||
/// is the parent of the image
|
||||
@Collection(ignore: {'path'})
|
||||
@Name('CacheImage')
|
||||
class Image {
|
||||
@Id()
|
||||
int id;
|
||||
// /// Represents a cover image for a library item
|
||||
// ///
|
||||
// /// stores 2 paths, one is thumbnail and the other is the full size image
|
||||
// /// both are optional
|
||||
// /// also stores last fetched date for the image
|
||||
// /// Id is passed as a parameter to the collection annotation (the lib_item_id)
|
||||
// /// also index the id
|
||||
// /// This is because the image is a part of the library item and the library item
|
||||
// /// is the parent of the image
|
||||
// @Collection(ignore: {'path'})
|
||||
// @Name('CacheImage')
|
||||
// class Image {
|
||||
// @Id()
|
||||
// int id;
|
||||
|
||||
String? thumbnailPath;
|
||||
String? imagePath;
|
||||
DateTime lastSaved;
|
||||
// String? thumbnailPath;
|
||||
// String? imagePath;
|
||||
// DateTime lastSaved;
|
||||
|
||||
Image({
|
||||
required this.id,
|
||||
this.thumbnailPath,
|
||||
this.imagePath,
|
||||
}) : lastSaved = DateTime.now();
|
||||
// Image({
|
||||
// required this.id,
|
||||
// this.thumbnailPath,
|
||||
// this.imagePath,
|
||||
// }) : lastSaved = DateTime.now();
|
||||
|
||||
/// returns the path to the image
|
||||
String? get path => thumbnailPath ?? imagePath;
|
||||
// /// returns the path to the image
|
||||
// String? get path => thumbnailPath ?? imagePath;
|
||||
|
||||
/// automatically updates the last fetched date when saving a new path
|
||||
void updatePath(String? thumbnailPath, String? imagePath) async {
|
||||
this.thumbnailPath = thumbnailPath;
|
||||
this.imagePath = imagePath;
|
||||
lastSaved = DateTime.now();
|
||||
}
|
||||
}
|
||||
// /// automatically updates the last fetched date when saving a new path
|
||||
// void updatePath(String? thumbnailPath, String? imagePath) async {
|
||||
// this.thumbnailPath = thumbnailPath;
|
||||
// this.imagePath = imagePath;
|
||||
// lastSaved = DateTime.now();
|
||||
// }
|
||||
// }
|
||||
|
|
|
|||
1009
lib/db/cache/schemas/image.g.dart
vendored
1009
lib/db/cache/schemas/image.g.dart
vendored
File diff suppressed because it is too large
Load diff
|
|
@ -1,6 +1,6 @@
|
|||
import 'dart:io';
|
||||
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:hive_plus_secure/hive_plus_secure.dart';
|
||||
import 'package:path/path.dart' as p;
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:vaani/main.dart';
|
||||
|
|
@ -13,12 +13,7 @@ Future initStorage() async {
|
|||
final dir = await getApplicationDocumentsDirectory();
|
||||
|
||||
// use vaani as the directory for hive
|
||||
final storageDir = Directory(
|
||||
p.join(
|
||||
dir.path,
|
||||
AppMetadata.appNameLowerCase,
|
||||
),
|
||||
);
|
||||
final storageDir = Directory(p.join(dir.path, AppMetadata.appNameLowerCase));
|
||||
await storageDir.create(recursive: true);
|
||||
|
||||
Hive.defaultDirectory = storageDir.path;
|
||||
|
|
|
|||
|
|
@ -1,29 +1,29 @@
|
|||
// a table to track preferences of player for each book
|
||||
import 'package:isar/isar.dart';
|
||||
// // a table to track preferences of player for each book
|
||||
// import 'package:isar/isar.dart';
|
||||
|
||||
part 'book_prefs.g.dart';
|
||||
// part 'book_prefs.g.dart';
|
||||
|
||||
/// stores the preferences of the player for a book
|
||||
@Collection()
|
||||
@Name('BookPrefs')
|
||||
class BookPrefs {
|
||||
@Id()
|
||||
int libItemId;
|
||||
// /// stores the preferences of the player for a book
|
||||
// @Collection()
|
||||
// @Name('BookPrefs')
|
||||
// class BookPrefs {
|
||||
// @Id()
|
||||
// int libItemId;
|
||||
|
||||
double? speed;
|
||||
// double? volume;
|
||||
// Duration? sleepTimer;
|
||||
// bool? showTotalProgress;
|
||||
// bool? showChapterProgress;
|
||||
// bool? useChapterInfo;
|
||||
// double? speed;
|
||||
// // double? volume;
|
||||
// // Duration? sleepTimer;
|
||||
// // bool? showTotalProgress;
|
||||
// // bool? showChapterProgress;
|
||||
// // bool? useChapterInfo;
|
||||
|
||||
BookPrefs({
|
||||
required this.libItemId,
|
||||
this.speed,
|
||||
// this.volume,
|
||||
// this.sleepTimer,
|
||||
// this.showTotalProgress,
|
||||
// this.showChapterProgress,
|
||||
// this.useChapterInfo,
|
||||
});
|
||||
}
|
||||
// BookPrefs({
|
||||
// required this.libItemId,
|
||||
// this.speed,
|
||||
// // this.volume,
|
||||
// // this.sleepTimer,
|
||||
// // this.showTotalProgress,
|
||||
// // this.showChapterProgress,
|
||||
// // this.useChapterInfo,
|
||||
// });
|
||||
// }
|
||||
|
|
|
|||
|
|
@ -1,496 +0,0 @@
|
|||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'book_prefs.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// _IsarCollectionGenerator
|
||||
// **************************************************************************
|
||||
|
||||
// coverage:ignore-file
|
||||
// ignore_for_file: duplicate_ignore, invalid_use_of_protected_member, lines_longer_than_80_chars, constant_identifier_names, avoid_js_rounded_ints, no_leading_underscores_for_local_identifiers, require_trailing_commas, unnecessary_parenthesis, unnecessary_raw_strings, unnecessary_null_in_if_null_operators, library_private_types_in_public_api, prefer_const_constructors
|
||||
// ignore_for_file: type=lint
|
||||
|
||||
extension GetBookPrefsCollection on Isar {
|
||||
IsarCollection<int, BookPrefs> get bookPrefs => this.collection();
|
||||
}
|
||||
|
||||
const BookPrefsSchema = IsarGeneratedSchema(
|
||||
schema: IsarSchema(
|
||||
name: 'BookPrefs',
|
||||
idName: 'libItemId',
|
||||
embedded: false,
|
||||
properties: [
|
||||
IsarPropertySchema(
|
||||
name: 'speed',
|
||||
type: IsarType.double,
|
||||
),
|
||||
],
|
||||
indexes: [],
|
||||
),
|
||||
converter: IsarObjectConverter<int, BookPrefs>(
|
||||
serialize: serializeBookPrefs,
|
||||
deserialize: deserializeBookPrefs,
|
||||
deserializeProperty: deserializeBookPrefsProp,
|
||||
),
|
||||
embeddedSchemas: [],
|
||||
);
|
||||
|
||||
@isarProtected
|
||||
int serializeBookPrefs(IsarWriter writer, BookPrefs object) {
|
||||
IsarCore.writeDouble(writer, 1, object.speed ?? double.nan);
|
||||
return object.libItemId;
|
||||
}
|
||||
|
||||
@isarProtected
|
||||
BookPrefs deserializeBookPrefs(IsarReader reader) {
|
||||
final int _libItemId;
|
||||
_libItemId = IsarCore.readId(reader);
|
||||
final double? _speed;
|
||||
{
|
||||
final value = IsarCore.readDouble(reader, 1);
|
||||
if (value.isNaN) {
|
||||
_speed = null;
|
||||
} else {
|
||||
_speed = value;
|
||||
}
|
||||
}
|
||||
final object = BookPrefs(
|
||||
libItemId: _libItemId,
|
||||
speed: _speed,
|
||||
);
|
||||
return object;
|
||||
}
|
||||
|
||||
@isarProtected
|
||||
dynamic deserializeBookPrefsProp(IsarReader reader, int property) {
|
||||
switch (property) {
|
||||
case 0:
|
||||
return IsarCore.readId(reader);
|
||||
case 1:
|
||||
{
|
||||
final value = IsarCore.readDouble(reader, 1);
|
||||
if (value.isNaN) {
|
||||
return null;
|
||||
} else {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
default:
|
||||
throw ArgumentError('Unknown property: $property');
|
||||
}
|
||||
}
|
||||
|
||||
sealed class _BookPrefsUpdate {
|
||||
bool call({
|
||||
required int libItemId,
|
||||
double? speed,
|
||||
});
|
||||
}
|
||||
|
||||
class _BookPrefsUpdateImpl implements _BookPrefsUpdate {
|
||||
const _BookPrefsUpdateImpl(this.collection);
|
||||
|
||||
final IsarCollection<int, BookPrefs> collection;
|
||||
|
||||
@override
|
||||
bool call({
|
||||
required int libItemId,
|
||||
Object? speed = ignore,
|
||||
}) {
|
||||
return collection.updateProperties([
|
||||
libItemId
|
||||
], {
|
||||
if (speed != ignore) 1: speed as double?,
|
||||
}) >
|
||||
0;
|
||||
}
|
||||
}
|
||||
|
||||
sealed class _BookPrefsUpdateAll {
|
||||
int call({
|
||||
required List<int> libItemId,
|
||||
double? speed,
|
||||
});
|
||||
}
|
||||
|
||||
class _BookPrefsUpdateAllImpl implements _BookPrefsUpdateAll {
|
||||
const _BookPrefsUpdateAllImpl(this.collection);
|
||||
|
||||
final IsarCollection<int, BookPrefs> collection;
|
||||
|
||||
@override
|
||||
int call({
|
||||
required List<int> libItemId,
|
||||
Object? speed = ignore,
|
||||
}) {
|
||||
return collection.updateProperties(libItemId, {
|
||||
if (speed != ignore) 1: speed as double?,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
extension BookPrefsUpdate on IsarCollection<int, BookPrefs> {
|
||||
_BookPrefsUpdate get update => _BookPrefsUpdateImpl(this);
|
||||
|
||||
_BookPrefsUpdateAll get updateAll => _BookPrefsUpdateAllImpl(this);
|
||||
}
|
||||
|
||||
sealed class _BookPrefsQueryUpdate {
|
||||
int call({
|
||||
double? speed,
|
||||
});
|
||||
}
|
||||
|
||||
class _BookPrefsQueryUpdateImpl implements _BookPrefsQueryUpdate {
|
||||
const _BookPrefsQueryUpdateImpl(this.query, {this.limit});
|
||||
|
||||
final IsarQuery<BookPrefs> query;
|
||||
final int? limit;
|
||||
|
||||
@override
|
||||
int call({
|
||||
Object? speed = ignore,
|
||||
}) {
|
||||
return query.updateProperties(limit: limit, {
|
||||
if (speed != ignore) 1: speed as double?,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
extension BookPrefsQueryUpdate on IsarQuery<BookPrefs> {
|
||||
_BookPrefsQueryUpdate get updateFirst =>
|
||||
_BookPrefsQueryUpdateImpl(this, limit: 1);
|
||||
|
||||
_BookPrefsQueryUpdate get updateAll => _BookPrefsQueryUpdateImpl(this);
|
||||
}
|
||||
|
||||
class _BookPrefsQueryBuilderUpdateImpl implements _BookPrefsQueryUpdate {
|
||||
const _BookPrefsQueryBuilderUpdateImpl(this.query, {this.limit});
|
||||
|
||||
final QueryBuilder<BookPrefs, BookPrefs, QOperations> query;
|
||||
final int? limit;
|
||||
|
||||
@override
|
||||
int call({
|
||||
Object? speed = ignore,
|
||||
}) {
|
||||
final q = query.build();
|
||||
try {
|
||||
return q.updateProperties(limit: limit, {
|
||||
if (speed != ignore) 1: speed as double?,
|
||||
});
|
||||
} finally {
|
||||
q.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension BookPrefsQueryBuilderUpdate
|
||||
on QueryBuilder<BookPrefs, BookPrefs, QOperations> {
|
||||
_BookPrefsQueryUpdate get updateFirst =>
|
||||
_BookPrefsQueryBuilderUpdateImpl(this, limit: 1);
|
||||
|
||||
_BookPrefsQueryUpdate get updateAll => _BookPrefsQueryBuilderUpdateImpl(this);
|
||||
}
|
||||
|
||||
extension BookPrefsQueryFilter
|
||||
on QueryBuilder<BookPrefs, BookPrefs, QFilterCondition> {
|
||||
QueryBuilder<BookPrefs, BookPrefs, QAfterFilterCondition> libItemIdEqualTo(
|
||||
int value,
|
||||
) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
EqualCondition(
|
||||
property: 0,
|
||||
value: value,
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<BookPrefs, BookPrefs, QAfterFilterCondition>
|
||||
libItemIdGreaterThan(
|
||||
int value,
|
||||
) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
GreaterCondition(
|
||||
property: 0,
|
||||
value: value,
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<BookPrefs, BookPrefs, QAfterFilterCondition>
|
||||
libItemIdGreaterThanOrEqualTo(
|
||||
int value,
|
||||
) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
GreaterOrEqualCondition(
|
||||
property: 0,
|
||||
value: value,
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<BookPrefs, BookPrefs, QAfterFilterCondition> libItemIdLessThan(
|
||||
int value,
|
||||
) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
LessCondition(
|
||||
property: 0,
|
||||
value: value,
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<BookPrefs, BookPrefs, QAfterFilterCondition>
|
||||
libItemIdLessThanOrEqualTo(
|
||||
int value,
|
||||
) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
LessOrEqualCondition(
|
||||
property: 0,
|
||||
value: value,
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<BookPrefs, BookPrefs, QAfterFilterCondition> libItemIdBetween(
|
||||
int lower,
|
||||
int upper,
|
||||
) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
BetweenCondition(
|
||||
property: 0,
|
||||
lower: lower,
|
||||
upper: upper,
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<BookPrefs, BookPrefs, QAfterFilterCondition> speedIsNull() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(const IsNullCondition(property: 1));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<BookPrefs, BookPrefs, QAfterFilterCondition> speedIsNotNull() {
|
||||
return QueryBuilder.apply(not(), (query) {
|
||||
return query.addFilterCondition(const IsNullCondition(property: 1));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<BookPrefs, BookPrefs, QAfterFilterCondition> speedEqualTo(
|
||||
double? value, {
|
||||
double epsilon = Filter.epsilon,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
EqualCondition(
|
||||
property: 1,
|
||||
value: value,
|
||||
epsilon: epsilon,
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<BookPrefs, BookPrefs, QAfterFilterCondition> speedGreaterThan(
|
||||
double? value, {
|
||||
double epsilon = Filter.epsilon,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
GreaterCondition(
|
||||
property: 1,
|
||||
value: value,
|
||||
epsilon: epsilon,
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<BookPrefs, BookPrefs, QAfterFilterCondition>
|
||||
speedGreaterThanOrEqualTo(
|
||||
double? value, {
|
||||
double epsilon = Filter.epsilon,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
GreaterOrEqualCondition(
|
||||
property: 1,
|
||||
value: value,
|
||||
epsilon: epsilon,
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<BookPrefs, BookPrefs, QAfterFilterCondition> speedLessThan(
|
||||
double? value, {
|
||||
double epsilon = Filter.epsilon,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
LessCondition(
|
||||
property: 1,
|
||||
value: value,
|
||||
epsilon: epsilon,
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<BookPrefs, BookPrefs, QAfterFilterCondition>
|
||||
speedLessThanOrEqualTo(
|
||||
double? value, {
|
||||
double epsilon = Filter.epsilon,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
LessOrEqualCondition(
|
||||
property: 1,
|
||||
value: value,
|
||||
epsilon: epsilon,
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<BookPrefs, BookPrefs, QAfterFilterCondition> speedBetween(
|
||||
double? lower,
|
||||
double? upper, {
|
||||
double epsilon = Filter.epsilon,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(
|
||||
BetweenCondition(
|
||||
property: 1,
|
||||
lower: lower,
|
||||
upper: upper,
|
||||
epsilon: epsilon,
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
extension BookPrefsQueryObject
|
||||
on QueryBuilder<BookPrefs, BookPrefs, QFilterCondition> {}
|
||||
|
||||
extension BookPrefsQuerySortBy on QueryBuilder<BookPrefs, BookPrefs, QSortBy> {
|
||||
QueryBuilder<BookPrefs, BookPrefs, QAfterSortBy> sortByLibItemId() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(0);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<BookPrefs, BookPrefs, QAfterSortBy> sortByLibItemIdDesc() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(0, sort: Sort.desc);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<BookPrefs, BookPrefs, QAfterSortBy> sortBySpeed() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(1);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<BookPrefs, BookPrefs, QAfterSortBy> sortBySpeedDesc() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(1, sort: Sort.desc);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
extension BookPrefsQuerySortThenBy
|
||||
on QueryBuilder<BookPrefs, BookPrefs, QSortThenBy> {
|
||||
QueryBuilder<BookPrefs, BookPrefs, QAfterSortBy> thenByLibItemId() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(0);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<BookPrefs, BookPrefs, QAfterSortBy> thenByLibItemIdDesc() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(0, sort: Sort.desc);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<BookPrefs, BookPrefs, QAfterSortBy> thenBySpeed() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(1);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<BookPrefs, BookPrefs, QAfterSortBy> thenBySpeedDesc() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(1, sort: Sort.desc);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
extension BookPrefsQueryWhereDistinct
|
||||
on QueryBuilder<BookPrefs, BookPrefs, QDistinct> {
|
||||
QueryBuilder<BookPrefs, BookPrefs, QAfterDistinct> distinctBySpeed() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addDistinctBy(1);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
extension BookPrefsQueryProperty1
|
||||
on QueryBuilder<BookPrefs, BookPrefs, QProperty> {
|
||||
QueryBuilder<BookPrefs, int, QAfterProperty> libItemIdProperty() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addProperty(0);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<BookPrefs, double?, QAfterProperty> speedProperty() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addProperty(1);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
extension BookPrefsQueryProperty2<R>
|
||||
on QueryBuilder<BookPrefs, R, QAfterProperty> {
|
||||
QueryBuilder<BookPrefs, (R, int), QAfterProperty> libItemIdProperty() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addProperty(0);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<BookPrefs, (R, double?), QAfterProperty> speedProperty() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addProperty(1);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
extension BookPrefsQueryProperty3<R1, R2>
|
||||
on QueryBuilder<BookPrefs, (R1, R2), QAfterProperty> {
|
||||
QueryBuilder<BookPrefs, (R1, R2, int), QOperations> libItemIdProperty() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addProperty(0);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<BookPrefs, (R1, R2, double?), QOperations> speedProperty() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addProperty(1);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
import 'package:hive/hive.dart';
|
||||
import 'package:hive_plus_secure/hive_plus_secure.dart';
|
||||
import 'package:vaani/features/per_book_settings/models/book_settings.dart';
|
||||
import 'package:vaani/settings/models/models.dart';
|
||||
|
||||
|
|
|
|||
|
|
@ -67,17 +67,13 @@ class AudiobookDownloadManager {
|
|||
|
||||
late StreamSubscription<TaskUpdate> _updatesSubscription;
|
||||
|
||||
Future<void> queueAudioBookDownload(
|
||||
LibraryItemExpanded item,
|
||||
) async {
|
||||
Future<void> queueAudioBookDownload(LibraryItemExpanded item) async {
|
||||
_logger.info('queuing download for item: ${item.id}');
|
||||
// create a download task for each file in the item
|
||||
final directory = await getApplicationSupportDirectory();
|
||||
for (final file in item.libraryFiles) {
|
||||
// check if the file is already downloaded
|
||||
if (isFileDownloaded(
|
||||
constructFilePath(directory, item, file),
|
||||
)) {
|
||||
if (isFileDownloaded(constructFilePath(directory, item, file))) {
|
||||
_logger.info('file already downloaded: ${file.metadata.filename}');
|
||||
continue;
|
||||
}
|
||||
|
|
@ -105,8 +101,7 @@ class AudiobookDownloadManager {
|
|||
Directory directory,
|
||||
LibraryItemExpanded item,
|
||||
LibraryFile file,
|
||||
) =>
|
||||
'${directory.path}/${item.relPath}/${file.metadata.filename}';
|
||||
) => '${directory.path}/${item.relPath}/${file.metadata.filename}';
|
||||
|
||||
void dispose() {
|
||||
_updatesSubscription.cancel();
|
||||
|
|
|
|||
|
|
@ -52,13 +52,9 @@ class DownloadManager extends _$DownloadManager {
|
|||
return manager;
|
||||
}
|
||||
|
||||
Future<void> queueAudioBookDownload(
|
||||
LibraryItemExpanded item,
|
||||
) async {
|
||||
Future<void> queueAudioBookDownload(LibraryItemExpanded item) async {
|
||||
_logger.fine('queueing download for ${item.id}');
|
||||
await state.queueAudioBookDownload(
|
||||
item,
|
||||
);
|
||||
await state.queueAudioBookDownload(item);
|
||||
}
|
||||
|
||||
Future<void> deleteDownloadedItem(LibraryItemExpanded item) async {
|
||||
|
|
@ -83,58 +79,57 @@ class ItemDownloadProgress extends _$ItemDownloadProgress {
|
|||
Future<double?> build(String id) async {
|
||||
final item = await ref.watch(libraryItemProvider(id).future);
|
||||
final manager = ref.read(downloadManagerProvider);
|
||||
manager.taskUpdateStream.map((taskUpdate) {
|
||||
if (taskUpdate is! TaskProgressUpdate) {
|
||||
return null;
|
||||
}
|
||||
if (taskUpdate.task.group == id) {
|
||||
return taskUpdate;
|
||||
}
|
||||
}).listen((task) async {
|
||||
if (task != null) {
|
||||
final totalSize = item.totalSize;
|
||||
// if total size is 0, return 0
|
||||
if (totalSize == 0) {
|
||||
state = const AsyncValue.data(0.0);
|
||||
return;
|
||||
}
|
||||
final downloadedFiles = await manager.getDownloadedFilesMetadata(item);
|
||||
// calculate total size of downloaded files and total size of item, then divide
|
||||
// to get percentage
|
||||
final downloadedSize = downloadedFiles.fold<int>(
|
||||
0,
|
||||
(previousValue, element) => previousValue + element.metadata.size,
|
||||
);
|
||||
manager.taskUpdateStream
|
||||
.map((taskUpdate) {
|
||||
if (taskUpdate is! TaskProgressUpdate) {
|
||||
return null;
|
||||
}
|
||||
if (taskUpdate.task.group == id) {
|
||||
return taskUpdate;
|
||||
}
|
||||
})
|
||||
.listen((task) async {
|
||||
if (task != null) {
|
||||
final totalSize = item.totalSize;
|
||||
// if total size is 0, return 0
|
||||
if (totalSize == 0) {
|
||||
state = const AsyncValue.data(0.0);
|
||||
return;
|
||||
}
|
||||
final downloadedFiles = await manager.getDownloadedFilesMetadata(
|
||||
item,
|
||||
);
|
||||
// calculate total size of downloaded files and total size of item, then divide
|
||||
// to get percentage
|
||||
final downloadedSize = downloadedFiles.fold<int>(
|
||||
0,
|
||||
(previousValue, element) => previousValue + element.metadata.size,
|
||||
);
|
||||
|
||||
final inProgressFileSize = task.progress * task.expectedFileSize;
|
||||
final totalDownloadedSize = downloadedSize + inProgressFileSize;
|
||||
final progress = totalDownloadedSize / totalSize;
|
||||
// if current progress is more than calculated progress, do not update
|
||||
if (progress < (state.valueOrNull ?? 0.0)) {
|
||||
return;
|
||||
}
|
||||
final inProgressFileSize = task.progress * task.expectedFileSize;
|
||||
final totalDownloadedSize = downloadedSize + inProgressFileSize;
|
||||
final progress = totalDownloadedSize / totalSize;
|
||||
// if current progress is more than calculated progress, do not update
|
||||
if (progress < (state.value ?? 0.0)) {
|
||||
return;
|
||||
}
|
||||
|
||||
state = AsyncValue.data(progress.clamp(0.0, 1.0));
|
||||
}
|
||||
});
|
||||
state = AsyncValue.data(progress.clamp(0.0, 1.0));
|
||||
}
|
||||
});
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@riverpod
|
||||
FutureOr<List<TaskRecord>> downloadHistory(
|
||||
Ref ref, {
|
||||
String? group,
|
||||
}) async {
|
||||
FutureOr<List<TaskRecord>> downloadHistory(Ref ref, {String? group}) async {
|
||||
return await FileDownloader().database.allRecords(group: group);
|
||||
}
|
||||
|
||||
@riverpod
|
||||
class IsItemDownloaded extends _$IsItemDownloaded {
|
||||
@override
|
||||
FutureOr<bool> build(
|
||||
LibraryItemExpanded item,
|
||||
) {
|
||||
FutureOr<bool> build(LibraryItemExpanded item) {
|
||||
final manager = ref.watch(downloadManagerProvider);
|
||||
return manager.isItemDownloaded(item);
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -11,9 +11,7 @@ class DownloadsPage extends HookConsumerWidget {
|
|||
final downloadHistory = ref.watch(downloadHistoryProvider());
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('Downloads'),
|
||||
),
|
||||
appBar: AppBar(title: const Text('Downloads')),
|
||||
body: Center(
|
||||
// history of downloads
|
||||
child: downloadHistory.when(
|
||||
|
|
|
|||
|
|
@ -6,24 +6,64 @@ part of 'search_controller.dart';
|
|||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
/// The controller for the search bar.
|
||||
|
||||
@ProviderFor(GlobalSearchController)
|
||||
final globalSearchControllerProvider = GlobalSearchControllerProvider._();
|
||||
|
||||
/// The controller for the search bar.
|
||||
final class GlobalSearchControllerProvider
|
||||
extends $NotifierProvider<GlobalSearchController, Raw<SearchController>> {
|
||||
/// The controller for the search bar.
|
||||
GlobalSearchControllerProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
retry: null,
|
||||
name: r'globalSearchControllerProvider',
|
||||
isAutoDispose: false,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$globalSearchControllerHash();
|
||||
|
||||
@$internal
|
||||
@override
|
||||
GlobalSearchController create() => GlobalSearchController();
|
||||
|
||||
/// {@macro riverpod.override_with_value}
|
||||
Override overrideWithValue(Raw<SearchController> value) {
|
||||
return $ProviderOverride(
|
||||
origin: this,
|
||||
providerOverride: $SyncValueProvider<Raw<SearchController>>(value),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
String _$globalSearchControllerHash() =>
|
||||
r'd854ace6f2e00a10fc33aba63051375f82ad1b10';
|
||||
|
||||
/// The controller for the search bar.
|
||||
///
|
||||
/// Copied from [GlobalSearchController].
|
||||
@ProviderFor(GlobalSearchController)
|
||||
final globalSearchControllerProvider =
|
||||
NotifierProvider<GlobalSearchController, Raw<SearchController>>.internal(
|
||||
GlobalSearchController.new,
|
||||
name: r'globalSearchControllerProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$globalSearchControllerHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
typedef _$GlobalSearchController = Notifier<Raw<SearchController>>;
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package
|
||||
abstract class _$GlobalSearchController
|
||||
extends $Notifier<Raw<SearchController>> {
|
||||
Raw<SearchController> build();
|
||||
@$mustCallSuper
|
||||
@override
|
||||
void runBuild() {
|
||||
final ref = this.ref as $Ref<Raw<SearchController>, Raw<SearchController>>;
|
||||
final element =
|
||||
ref.element
|
||||
as $ClassProviderElement<
|
||||
AnyNotifier<Raw<SearchController>, Raw<SearchController>>,
|
||||
Raw<SearchController>,
|
||||
Object?,
|
||||
Object?
|
||||
>;
|
||||
element.handleCreate(ref, build);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,186 +6,94 @@ part of 'search_result_provider.dart';
|
|||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$searchResultHash() => r'33785de298ad0d53c9d21e8fec88ba2f22f1363f';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
_SystemHash._();
|
||||
|
||||
static int combine(int hash, int value) {
|
||||
// ignore: parameter_assignments
|
||||
hash = 0x1fffffff & (hash + value);
|
||||
// ignore: parameter_assignments
|
||||
hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
|
||||
return hash ^ (hash >> 6);
|
||||
}
|
||||
|
||||
static int finish(int hash) {
|
||||
// ignore: parameter_assignments
|
||||
hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
|
||||
// ignore: parameter_assignments
|
||||
hash = hash ^ (hash >> 11);
|
||||
return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
|
||||
}
|
||||
}
|
||||
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
/// The provider for the search result.
|
||||
///
|
||||
/// Copied from [searchResult].
|
||||
|
||||
@ProviderFor(searchResult)
|
||||
const searchResultProvider = SearchResultFamily();
|
||||
final searchResultProvider = SearchResultFamily._();
|
||||
|
||||
/// The provider for the search result.
|
||||
///
|
||||
/// Copied from [searchResult].
|
||||
class SearchResultFamily extends Family<AsyncValue<LibrarySearchResponse?>> {
|
||||
/// The provider for the search result.
|
||||
///
|
||||
/// Copied from [searchResult].
|
||||
const SearchResultFamily();
|
||||
|
||||
final class SearchResultProvider
|
||||
extends
|
||||
$FunctionalProvider<
|
||||
AsyncValue<LibrarySearchResponse?>,
|
||||
LibrarySearchResponse?,
|
||||
FutureOr<LibrarySearchResponse?>
|
||||
>
|
||||
with
|
||||
$FutureModifier<LibrarySearchResponse?>,
|
||||
$FutureProvider<LibrarySearchResponse?> {
|
||||
/// The provider for the search result.
|
||||
///
|
||||
/// Copied from [searchResult].
|
||||
SearchResultProvider call(
|
||||
String query, {
|
||||
int limit = 25,
|
||||
}) {
|
||||
return SearchResultProvider(
|
||||
query,
|
||||
limit: limit,
|
||||
);
|
||||
SearchResultProvider._({
|
||||
required SearchResultFamily super.from,
|
||||
required (String, {int limit}) super.argument,
|
||||
}) : super(
|
||||
retry: null,
|
||||
name: r'searchResultProvider',
|
||||
isAutoDispose: true,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$searchResultHash();
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return r'searchResultProvider'
|
||||
''
|
||||
'$argument';
|
||||
}
|
||||
|
||||
@$internal
|
||||
@override
|
||||
SearchResultProvider getProviderOverride(
|
||||
covariant SearchResultProvider provider,
|
||||
) {
|
||||
return call(
|
||||
provider.query,
|
||||
limit: provider.limit,
|
||||
);
|
||||
}
|
||||
|
||||
static const Iterable<ProviderOrFamily>? _dependencies = null;
|
||||
$FutureProviderElement<LibrarySearchResponse?> $createElement(
|
||||
$ProviderPointer pointer,
|
||||
) => $FutureProviderElement(pointer);
|
||||
|
||||
@override
|
||||
Iterable<ProviderOrFamily>? get dependencies => _dependencies;
|
||||
|
||||
static const Iterable<ProviderOrFamily>? _allTransitiveDependencies = null;
|
||||
|
||||
@override
|
||||
Iterable<ProviderOrFamily>? get allTransitiveDependencies =>
|
||||
_allTransitiveDependencies;
|
||||
|
||||
@override
|
||||
String? get name => r'searchResultProvider';
|
||||
}
|
||||
|
||||
/// The provider for the search result.
|
||||
///
|
||||
/// Copied from [searchResult].
|
||||
class SearchResultProvider
|
||||
extends AutoDisposeFutureProvider<LibrarySearchResponse?> {
|
||||
/// The provider for the search result.
|
||||
///
|
||||
/// Copied from [searchResult].
|
||||
SearchResultProvider(
|
||||
String query, {
|
||||
int limit = 25,
|
||||
}) : this._internal(
|
||||
(ref) => searchResult(
|
||||
ref as SearchResultRef,
|
||||
query,
|
||||
limit: limit,
|
||||
),
|
||||
from: searchResultProvider,
|
||||
name: r'searchResultProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$searchResultHash,
|
||||
dependencies: SearchResultFamily._dependencies,
|
||||
allTransitiveDependencies:
|
||||
SearchResultFamily._allTransitiveDependencies,
|
||||
query: query,
|
||||
limit: limit,
|
||||
);
|
||||
|
||||
SearchResultProvider._internal(
|
||||
super._createNotifier, {
|
||||
required super.name,
|
||||
required super.dependencies,
|
||||
required super.allTransitiveDependencies,
|
||||
required super.debugGetCreateSourceHash,
|
||||
required super.from,
|
||||
required this.query,
|
||||
required this.limit,
|
||||
}) : super.internal();
|
||||
|
||||
final String query;
|
||||
final int limit;
|
||||
|
||||
@override
|
||||
Override overrideWith(
|
||||
FutureOr<LibrarySearchResponse?> Function(SearchResultRef provider) create,
|
||||
) {
|
||||
return ProviderOverride(
|
||||
origin: this,
|
||||
override: SearchResultProvider._internal(
|
||||
(ref) => create(ref as SearchResultRef),
|
||||
from: from,
|
||||
name: null,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
debugGetCreateSourceHash: null,
|
||||
query: query,
|
||||
limit: limit,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
AutoDisposeFutureProviderElement<LibrarySearchResponse?> createElement() {
|
||||
return _SearchResultProviderElement(this);
|
||||
FutureOr<LibrarySearchResponse?> create(Ref ref) {
|
||||
final argument = this.argument as (String, {int limit});
|
||||
return searchResult(ref, argument.$1, limit: argument.limit);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is SearchResultProvider &&
|
||||
other.query == query &&
|
||||
other.limit == limit;
|
||||
return other is SearchResultProvider && other.argument == argument;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
||||
hash = _SystemHash.combine(hash, query.hashCode);
|
||||
hash = _SystemHash.combine(hash, limit.hashCode);
|
||||
|
||||
return _SystemHash.finish(hash);
|
||||
return argument.hashCode;
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||
// ignore: unused_element
|
||||
mixin SearchResultRef on AutoDisposeFutureProviderRef<LibrarySearchResponse?> {
|
||||
/// The parameter `query` of this provider.
|
||||
String get query;
|
||||
String _$searchResultHash() => r'33785de298ad0d53c9d21e8fec88ba2f22f1363f';
|
||||
|
||||
/// The parameter `limit` of this provider.
|
||||
int get limit;
|
||||
}
|
||||
/// The provider for the search result.
|
||||
|
||||
class _SearchResultProviderElement
|
||||
extends AutoDisposeFutureProviderElement<LibrarySearchResponse?>
|
||||
with SearchResultRef {
|
||||
_SearchResultProviderElement(super.provider);
|
||||
final class SearchResultFamily extends $Family
|
||||
with
|
||||
$FunctionalFamilyOverride<
|
||||
FutureOr<LibrarySearchResponse?>,
|
||||
(String, {int limit})
|
||||
> {
|
||||
SearchResultFamily._()
|
||||
: super(
|
||||
retry: null,
|
||||
name: r'searchResultProvider',
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
isAutoDispose: true,
|
||||
);
|
||||
|
||||
/// The provider for the search result.
|
||||
|
||||
SearchResultProvider call(String query, {int limit = 25}) =>
|
||||
SearchResultProvider._(argument: (query, limit: limit), from: this);
|
||||
|
||||
@override
|
||||
String get query => (origin as SearchResultProvider).query;
|
||||
@override
|
||||
int get limit => (origin as SearchResultProvider).limit;
|
||||
String toString() => r'searchResultProvider';
|
||||
}
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package
|
||||
|
|
|
|||
|
|
@ -28,18 +28,14 @@ class ExplorePage extends HookConsumerWidget {
|
|||
final settings = ref.watch(appSettingsProvider);
|
||||
final api = ref.watch(authenticatedApiProvider);
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('Explore'),
|
||||
),
|
||||
appBar: AppBar(title: const Text('Explore')),
|
||||
body: const MySearchBar(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class MySearchBar extends HookConsumerWidget {
|
||||
const MySearchBar({
|
||||
super.key,
|
||||
});
|
||||
const MySearchBar({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
|
|
@ -61,8 +57,11 @@ class MySearchBar extends HookConsumerWidget {
|
|||
currentQuery = query;
|
||||
|
||||
// In a real application, there should be some error handling here.
|
||||
final options = await api.libraries
|
||||
.search(libraryId: settings.activeLibraryId!, query: query, limit: 3);
|
||||
final options = await api.libraries.search(
|
||||
libraryId: settings.activeLibraryId!,
|
||||
query: query,
|
||||
limit: 3,
|
||||
);
|
||||
|
||||
// If another search happened after this one, throw away these options.
|
||||
if (currentQuery != query) {
|
||||
|
|
@ -97,11 +96,10 @@ class MySearchBar extends HookConsumerWidget {
|
|||
// opacity: 0.5 for the hint text
|
||||
hintStyle: WidgetStatePropertyAll(
|
||||
Theme.of(context).textTheme.bodyMedium!.copyWith(
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.onSurface
|
||||
.withValues(alpha: 0.5),
|
||||
),
|
||||
color: Theme.of(
|
||||
context,
|
||||
).colorScheme.onSurface.withValues(alpha: 0.5),
|
||||
),
|
||||
),
|
||||
textInputAction: TextInputAction.search,
|
||||
onTapOutside: (_) {
|
||||
|
|
@ -120,12 +118,7 @@ class MySearchBar extends HookConsumerWidget {
|
|||
);
|
||||
},
|
||||
viewOnSubmitted: (value) {
|
||||
context.pushNamed(
|
||||
Routes.search.name,
|
||||
queryParameters: {
|
||||
'q': value,
|
||||
},
|
||||
);
|
||||
context.pushNamed(Routes.search.name, queryParameters: {'q': value});
|
||||
},
|
||||
suggestionsBuilder: (context, controller) async {
|
||||
// check if the search controller is empty
|
||||
|
|
@ -191,14 +184,12 @@ List<Widget> buildBookSearchResult(
|
|||
SearchResultMiniSection(
|
||||
// title: 'Books',
|
||||
category: SearchResultCategory.books,
|
||||
options: options.book.map(
|
||||
(result) {
|
||||
// convert result to a book object
|
||||
final book = result.libraryItem.media.asBookExpanded;
|
||||
final metadata = book.metadata.asBookMetadataExpanded;
|
||||
return BookSearchResultMini(book: book, metadata: metadata);
|
||||
},
|
||||
),
|
||||
options: options.book.map((result) {
|
||||
// convert result to a book object
|
||||
final book = result.libraryItem.media.asBookExpanded;
|
||||
final metadata = book.metadata.asBookMetadataExpanded;
|
||||
return BookSearchResultMini(book: book, metadata: metadata);
|
||||
}),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
@ -207,11 +198,9 @@ List<Widget> buildBookSearchResult(
|
|||
SearchResultMiniSection(
|
||||
// title: 'Authors',
|
||||
category: SearchResultCategory.authors,
|
||||
options: options.authors.map(
|
||||
(result) {
|
||||
return ListTile(title: Text(result.name));
|
||||
},
|
||||
),
|
||||
options: options.authors.map((result) {
|
||||
return ListTile(title: Text(result.name));
|
||||
}),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
@ -232,7 +221,7 @@ class BookSearchResultMini extends HookConsumerWidget {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final item = ref.watch(libraryItemProvider(book.libraryItemId)).valueOrNull;
|
||||
final item = ref.watch(libraryItemProvider(book.libraryItemId)).value;
|
||||
final image = item == null
|
||||
? const AsyncValue.loading()
|
||||
: ref.watch(coverImageProvider(item.id));
|
||||
|
|
@ -245,10 +234,7 @@ class BookSearchResultMini extends HookConsumerWidget {
|
|||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(5),
|
||||
child: image.when(
|
||||
data: (bytes) => Image.memory(
|
||||
bytes,
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
data: (bytes) => Image.memory(bytes, fit: BoxFit.cover),
|
||||
loading: () => const BookCoverSkeleton(),
|
||||
error: (error, _) => const Icon(Icons.error),
|
||||
),
|
||||
|
|
@ -259,11 +245,7 @@ class BookSearchResultMini extends HookConsumerWidget {
|
|||
subtitle: Text(
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
metadata.authors
|
||||
.map(
|
||||
(author) => author.name,
|
||||
)
|
||||
.join(', '),
|
||||
metadata.authors.map((author) => author.name).join(', '),
|
||||
),
|
||||
onTap: () {
|
||||
// navigate to the book details page
|
||||
|
|
|
|||
|
|
@ -5,13 +5,7 @@ import 'package:vaani/features/explore/providers/search_result_provider.dart';
|
|||
import 'package:vaani/features/explore/view/explore_page.dart';
|
||||
import 'package:vaani/shared/extensions/model_conversions.dart';
|
||||
|
||||
enum SearchResultCategory {
|
||||
books,
|
||||
authors,
|
||||
series,
|
||||
tags,
|
||||
narrators,
|
||||
}
|
||||
enum SearchResultCategory { books, authors, series, tags, narrators }
|
||||
|
||||
class SearchResultPage extends HookConsumerWidget {
|
||||
const SearchResultPage({
|
||||
|
|
@ -41,9 +35,7 @@ class SearchResultPage extends HookConsumerWidget {
|
|||
body: results.when(
|
||||
data: (options) {
|
||||
if (options == null) {
|
||||
return Container(
|
||||
child: const Text('No data found'),
|
||||
);
|
||||
return Container(child: const Text('No data found'));
|
||||
}
|
||||
if (options is BookLibrarySearchResponse) {
|
||||
if (category == null) {
|
||||
|
|
@ -51,18 +43,15 @@ class SearchResultPage extends HookConsumerWidget {
|
|||
}
|
||||
return switch (category!) {
|
||||
SearchResultCategory.books => ListView.builder(
|
||||
itemCount: options.book.length,
|
||||
itemBuilder: (context, index) {
|
||||
final book =
|
||||
options.book[index].libraryItem.media.asBookExpanded;
|
||||
final metadata = book.metadata.asBookMetadataExpanded;
|
||||
itemCount: options.book.length,
|
||||
itemBuilder: (context, index) {
|
||||
final book =
|
||||
options.book[index].libraryItem.media.asBookExpanded;
|
||||
final metadata = book.metadata.asBookMetadataExpanded;
|
||||
|
||||
return BookSearchResultMini(
|
||||
book: book,
|
||||
metadata: metadata,
|
||||
);
|
||||
},
|
||||
),
|
||||
return BookSearchResultMini(book: book, metadata: metadata);
|
||||
},
|
||||
),
|
||||
SearchResultCategory.authors => Container(),
|
||||
SearchResultCategory.series => Container(),
|
||||
SearchResultCategory.tags => Container(),
|
||||
|
|
@ -71,12 +60,8 @@ class SearchResultPage extends HookConsumerWidget {
|
|||
}
|
||||
return null;
|
||||
},
|
||||
loading: () => const Center(
|
||||
child: CircularProgressIndicator(),
|
||||
),
|
||||
error: (error, stackTrace) => Center(
|
||||
child: Text('Error: $error'),
|
||||
),
|
||||
loading: () => const Center(child: CircularProgressIndicator()),
|
||||
error: (error, stackTrace) => Center(child: Text('Error: $error')),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,16 +26,13 @@ import 'package:vaani/shared/extensions/model_conversions.dart';
|
|||
import 'package:vaani/shared/utils.dart';
|
||||
|
||||
class LibraryItemActions extends HookConsumerWidget {
|
||||
const LibraryItemActions({
|
||||
super.key,
|
||||
required this.id,
|
||||
});
|
||||
const LibraryItemActions({super.key, required this.id});
|
||||
|
||||
final String id;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final item = ref.watch(libraryItemProvider(id)).valueOrNull;
|
||||
final item = ref.watch(libraryItemProvider(id)).value;
|
||||
if (item == null) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
|
|
@ -68,9 +65,7 @@ class LibraryItemActions extends HookConsumerWidget {
|
|||
// read list button
|
||||
IconButton(
|
||||
onPressed: () {},
|
||||
icon: const Icon(
|
||||
Icons.playlist_add_rounded,
|
||||
),
|
||||
icon: const Icon(Icons.playlist_add_rounded),
|
||||
),
|
||||
// share button
|
||||
IconButton(
|
||||
|
|
@ -79,8 +74,9 @@ class LibraryItemActions extends HookConsumerWidget {
|
|||
var currentServerUrl =
|
||||
apiSettings.activeServer!.serverUrl;
|
||||
if (!currentServerUrl.hasScheme) {
|
||||
currentServerUrl =
|
||||
Uri.https(currentServerUrl.toString());
|
||||
currentServerUrl = Uri.https(
|
||||
currentServerUrl.toString(),
|
||||
);
|
||||
}
|
||||
handleLaunchUrl(
|
||||
Uri.parse(
|
||||
|
|
@ -140,7 +136,8 @@ class LibraryItemActions extends HookConsumerWidget {
|
|||
.database
|
||||
.deleteRecordWithId(
|
||||
record
|
||||
.task.taskId,
|
||||
.task
|
||||
.taskId,
|
||||
);
|
||||
Navigator.pop(context);
|
||||
},
|
||||
|
|
@ -161,8 +158,8 @@ class LibraryItemActions extends HookConsumerWidget {
|
|||
// open the file location
|
||||
final didOpen =
|
||||
await FileDownloader().openFile(
|
||||
task: record.task,
|
||||
);
|
||||
task: record.task,
|
||||
);
|
||||
|
||||
if (!didOpen) {
|
||||
appLogger.warning(
|
||||
|
|
@ -182,16 +179,13 @@ class LibraryItemActions extends HookConsumerWidget {
|
|||
loading: () => const Center(
|
||||
child: CircularProgressIndicator(),
|
||||
),
|
||||
error: (error, stackTrace) => Center(
|
||||
child: Text('Error: $error'),
|
||||
),
|
||||
error: (error, stackTrace) =>
|
||||
Center(child: Text('Error: $error')),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons.more_vert_rounded,
|
||||
),
|
||||
icon: const Icon(Icons.more_vert_rounded),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
|
@ -206,25 +200,20 @@ class LibraryItemActions extends HookConsumerWidget {
|
|||
}
|
||||
|
||||
class LibItemDownloadButton extends HookConsumerWidget {
|
||||
const LibItemDownloadButton({
|
||||
super.key,
|
||||
required this.item,
|
||||
});
|
||||
const LibItemDownloadButton({super.key, required this.item});
|
||||
|
||||
final shelfsdk.LibraryItemExpanded item;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final isItemDownloaded = ref.watch(isItemDownloadedProvider(item));
|
||||
if (isItemDownloaded.valueOrNull ?? false) {
|
||||
if (isItemDownloaded.value ?? false) {
|
||||
return AlreadyItemDownloadedButton(item: item);
|
||||
}
|
||||
final isItemDownloading = ref.watch(isItemDownloadingProvider(item.id));
|
||||
|
||||
return isItemDownloading
|
||||
? ItemCurrentlyInDownloadQueue(
|
||||
item: item,
|
||||
)
|
||||
? ItemCurrentlyInDownloadQueue(item: item)
|
||||
: IconButton(
|
||||
onPressed: () {
|
||||
appLogger.fine('Pressed download button');
|
||||
|
|
@ -233,18 +222,13 @@ class LibItemDownloadButton extends HookConsumerWidget {
|
|||
.read(downloadManagerProvider.notifier)
|
||||
.queueAudioBookDownload(item);
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons.download_rounded,
|
||||
),
|
||||
icon: const Icon(Icons.download_rounded),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ItemCurrentlyInDownloadQueue extends HookConsumerWidget {
|
||||
const ItemCurrentlyInDownloadQueue({
|
||||
super.key,
|
||||
required this.item,
|
||||
});
|
||||
const ItemCurrentlyInDownloadQueue({super.key, required this.item});
|
||||
|
||||
final shelfsdk.LibraryItemExpanded item;
|
||||
|
||||
|
|
@ -252,7 +236,7 @@ class ItemCurrentlyInDownloadQueue extends HookConsumerWidget {
|
|||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final progress = ref
|
||||
.watch(itemDownloadProgressProvider(item.id))
|
||||
.valueOrNull
|
||||
.value
|
||||
?.clamp(0.05, 1.0);
|
||||
|
||||
if (progress == 1) {
|
||||
|
|
@ -263,17 +247,12 @@ class ItemCurrentlyInDownloadQueue extends HookConsumerWidget {
|
|||
return Stack(
|
||||
alignment: Alignment.center,
|
||||
children: [
|
||||
CircularProgressIndicator(
|
||||
value: progress,
|
||||
strokeWidth: 2,
|
||||
),
|
||||
CircularProgressIndicator(value: progress, strokeWidth: 2),
|
||||
const Icon(
|
||||
Icons.download,
|
||||
// color: Theme.of(context).progressIndicatorTheme.color,
|
||||
)
|
||||
.animate(
|
||||
onPlay: (controller) => controller.repeat(),
|
||||
Icons.download,
|
||||
// color: Theme.of(context).progressIndicatorTheme.color,
|
||||
)
|
||||
.animate(onPlay: (controller) => controller.repeat())
|
||||
.fade(
|
||||
duration: shimmerDuration,
|
||||
end: 1,
|
||||
|
|
@ -292,10 +271,7 @@ class ItemCurrentlyInDownloadQueue extends HookConsumerWidget {
|
|||
}
|
||||
|
||||
class AlreadyItemDownloadedButton extends HookConsumerWidget {
|
||||
const AlreadyItemDownloadedButton({
|
||||
super.key,
|
||||
required this.item,
|
||||
});
|
||||
const AlreadyItemDownloadedButton({super.key, required this.item});
|
||||
|
||||
final shelfsdk.LibraryItemExpanded item;
|
||||
|
||||
|
|
@ -317,25 +293,18 @@ class AlreadyItemDownloadedButton extends HookConsumerWidget {
|
|||
top: 8.0,
|
||||
bottom: (isBookPlaying ? playerMinHeight : 0) + 8,
|
||||
),
|
||||
child: DownloadSheet(
|
||||
item: item,
|
||||
),
|
||||
child: DownloadSheet(item: item),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons.download_done_rounded,
|
||||
),
|
||||
icon: const Icon(Icons.download_done_rounded),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class DownloadSheet extends HookConsumerWidget {
|
||||
const DownloadSheet({
|
||||
super.key,
|
||||
required this.item,
|
||||
});
|
||||
const DownloadSheet({super.key, required this.item});
|
||||
|
||||
final shelfsdk.LibraryItemExpanded item;
|
||||
|
||||
|
|
@ -367,9 +336,7 @@ class DownloadSheet extends HookConsumerWidget {
|
|||
// ),
|
||||
ListTile(
|
||||
title: const Text('Delete'),
|
||||
leading: const Icon(
|
||||
Icons.delete_rounded,
|
||||
),
|
||||
leading: const Icon(Icons.delete_rounded),
|
||||
onTap: () async {
|
||||
// show the delete dialog
|
||||
final wasDeleted = await showDialog<bool>(
|
||||
|
|
@ -387,9 +354,7 @@ class DownloadSheet extends HookConsumerWidget {
|
|||
// delete the file
|
||||
ref
|
||||
.read(downloadManagerProvider.notifier)
|
||||
.deleteDownloadedItem(
|
||||
item,
|
||||
);
|
||||
.deleteDownloadedItem(item);
|
||||
GoRouter.of(context).pop(true);
|
||||
},
|
||||
child: const Text('Yes'),
|
||||
|
|
@ -409,11 +374,7 @@ class DownloadSheet extends HookConsumerWidget {
|
|||
appLogger.fine('Deleted ${item.media.metadata.title}');
|
||||
GoRouter.of(context).pop();
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(
|
||||
'Deleted ${item.media.metadata.title}',
|
||||
),
|
||||
),
|
||||
SnackBar(content: Text('Deleted ${item.media.metadata.title}')),
|
||||
);
|
||||
}
|
||||
},
|
||||
|
|
@ -424,9 +385,7 @@ class DownloadSheet extends HookConsumerWidget {
|
|||
}
|
||||
|
||||
class _LibraryItemPlayButton extends HookConsumerWidget {
|
||||
const _LibraryItemPlayButton({
|
||||
required this.item,
|
||||
});
|
||||
const _LibraryItemPlayButton({required this.item});
|
||||
|
||||
final shelfsdk.LibraryItemExpanded item;
|
||||
|
||||
|
|
@ -477,9 +436,7 @@ class _LibraryItemPlayButton extends HookConsumerWidget {
|
|||
),
|
||||
label: Text(getPlayDisplayText()),
|
||||
style: ElevatedButton.styleFrom(
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
),
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(4)),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
@ -502,11 +459,11 @@ class DynamicItemPlayIcon extends StatelessWidget {
|
|||
return Icon(
|
||||
isCurrentBookSetInPlayer
|
||||
? isPlayingThisBook
|
||||
? Icons.pause_rounded
|
||||
: Icons.play_arrow_rounded
|
||||
? Icons.pause_rounded
|
||||
: Icons.play_arrow_rounded
|
||||
: isBookCompleted
|
||||
? Icons.replay_rounded
|
||||
: Icons.play_arrow_rounded,
|
||||
? Icons.replay_rounded
|
||||
: Icons.play_arrow_rounded,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -529,8 +486,9 @@ Future<void> libraryItemPlayButtonOnPressed({
|
|||
appLogger.info('Setting the book ${book.libraryItemId}');
|
||||
appLogger.info('Initial position: ${userMediaProgress?.currentTime}');
|
||||
final downloadManager = ref.watch(simpleDownloadManagerProvider);
|
||||
final libItem =
|
||||
await ref.read(libraryItemProvider(book.libraryItemId).future);
|
||||
final libItem = await ref.read(
|
||||
libraryItemProvider(book.libraryItemId).future,
|
||||
);
|
||||
final downloadedUris = await downloadManager.getDownloadedFilesUri(libItem);
|
||||
setSourceFuture = player.setSourceAudiobook(
|
||||
book,
|
||||
|
|
@ -546,8 +504,9 @@ Future<void> libraryItemPlayButtonOnPressed({
|
|||
}
|
||||
}
|
||||
// set the volume as this is the first time playing and dismissing causes the volume to go to 0
|
||||
var bookPlayerSettings =
|
||||
ref.read(bookSettingsProvider(book.libraryItemId)).playerSettings;
|
||||
var bookPlayerSettings = ref
|
||||
.read(bookSettingsProvider(book.libraryItemId))
|
||||
.playerSettings;
|
||||
var appPlayerSettings = ref.read(appSettingsProvider).playerSettings;
|
||||
|
||||
var configurePlayerForEveryBook =
|
||||
|
|
@ -559,14 +518,14 @@ Future<void> libraryItemPlayButtonOnPressed({
|
|||
player.setVolume(
|
||||
configurePlayerForEveryBook
|
||||
? bookPlayerSettings.preferredDefaultVolume ??
|
||||
appPlayerSettings.preferredDefaultVolume
|
||||
appPlayerSettings.preferredDefaultVolume
|
||||
: appPlayerSettings.preferredDefaultVolume,
|
||||
),
|
||||
// set the speed
|
||||
player.setSpeed(
|
||||
configurePlayerForEveryBook
|
||||
? bookPlayerSettings.preferredDefaultSpeed ??
|
||||
appPlayerSettings.preferredDefaultSpeed
|
||||
appPlayerSettings.preferredDefaultSpeed
|
||||
: appPlayerSettings.preferredDefaultSpeed,
|
||||
),
|
||||
]);
|
||||
|
|
|
|||
|
|
@ -42,14 +42,13 @@ class LibraryItemHeroSection extends HookConsumerWidget {
|
|||
child: Column(
|
||||
children: [
|
||||
Hero(
|
||||
tag: HeroTagPrefixes.bookCover +
|
||||
tag:
|
||||
HeroTagPrefixes.bookCover +
|
||||
itemId +
|
||||
(extraMap?.heroTagSuffix ?? ''),
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
child: _BookCover(
|
||||
itemId: itemId,
|
||||
),
|
||||
child: _BookCover(itemId: itemId),
|
||||
),
|
||||
),
|
||||
// a progress bar
|
||||
|
|
@ -59,9 +58,7 @@ class LibraryItemHeroSection extends HookConsumerWidget {
|
|||
right: 8.0,
|
||||
left: 8.0,
|
||||
),
|
||||
child: _LibraryItemProgressIndicator(
|
||||
id: itemId,
|
||||
),
|
||||
child: _LibraryItemProgressIndicator(id: itemId),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
|
@ -77,10 +74,7 @@ class LibraryItemHeroSection extends HookConsumerWidget {
|
|||
}
|
||||
|
||||
class _BookDetails extends HookConsumerWidget {
|
||||
const _BookDetails({
|
||||
required this.id,
|
||||
this.extraMap,
|
||||
});
|
||||
const _BookDetails({required this.id, this.extraMap});
|
||||
|
||||
final String id;
|
||||
final LibraryItemExtras? extraMap;
|
||||
|
|
@ -90,7 +84,7 @@ class _BookDetails extends HookConsumerWidget {
|
|||
final itemFromApi = ref.watch(libraryItemProvider(id));
|
||||
|
||||
final itemBookMetadata =
|
||||
itemFromApi.valueOrNull?.media.metadata.asBookMetadataExpanded;
|
||||
itemFromApi.value?.media.metadata.asBookMetadataExpanded;
|
||||
|
||||
return Expanded(
|
||||
child: Padding(
|
||||
|
|
@ -99,10 +93,7 @@ class _BookDetails extends HookConsumerWidget {
|
|||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
_BookTitle(
|
||||
extraMap: extraMap,
|
||||
itemBookMetadata: itemBookMetadata,
|
||||
),
|
||||
_BookTitle(extraMap: extraMap, itemBookMetadata: itemBookMetadata),
|
||||
Container(
|
||||
margin: const EdgeInsets.symmetric(vertical: 16),
|
||||
child: Column(
|
||||
|
|
@ -134,16 +125,14 @@ class _BookDetails extends HookConsumerWidget {
|
|||
}
|
||||
|
||||
class _LibraryItemProgressIndicator extends HookConsumerWidget {
|
||||
const _LibraryItemProgressIndicator({
|
||||
required this.id,
|
||||
});
|
||||
const _LibraryItemProgressIndicator({required this.id});
|
||||
|
||||
final String id;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final player = ref.watch(audiobookPlayerProvider);
|
||||
final libraryItem = ref.watch(libraryItemProvider(id)).valueOrNull;
|
||||
final libraryItem = ref.watch(libraryItemProvider(id)).value;
|
||||
if (libraryItem == null) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
|
|
@ -157,13 +146,15 @@ class _LibraryItemProgressIndicator extends HookConsumerWidget {
|
|||
Duration remainingTime;
|
||||
if (player.book?.libraryItemId == libraryItem.id) {
|
||||
// final positionStream = useStream(player.slowPositionStream);
|
||||
progress = (player.positionInBook).inSeconds /
|
||||
progress =
|
||||
(player.positionInBook).inSeconds /
|
||||
libraryItem.media.asBookExpanded.duration.inSeconds;
|
||||
remainingTime =
|
||||
libraryItem.media.asBookExpanded.duration - player.positionInBook;
|
||||
} else {
|
||||
progress = mediaProgress?.progress ?? 0;
|
||||
remainingTime = (libraryItem.media.asBookExpanded.duration -
|
||||
remainingTime =
|
||||
(libraryItem.media.asBookExpanded.duration -
|
||||
mediaProgress!.currentTime);
|
||||
}
|
||||
|
||||
|
|
@ -190,20 +181,17 @@ class _LibraryItemProgressIndicator extends HookConsumerWidget {
|
|||
semanticsLabel: 'Book progress',
|
||||
semanticsValue: '${progressInPercent.toStringAsFixed(2)}%',
|
||||
),
|
||||
const SizedBox.square(
|
||||
dimension: 4.0,
|
||||
),
|
||||
const SizedBox.square(dimension: 4.0),
|
||||
// time remaining
|
||||
Text(
|
||||
// only show 2 decimal places
|
||||
'${remainingTime.smartBinaryFormat} left',
|
||||
|
||||
style: Theme.of(context).textTheme.bodySmall?.copyWith(
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.onSurface
|
||||
.withValues(alpha: 0.75),
|
||||
),
|
||||
color: Theme.of(
|
||||
context,
|
||||
).colorScheme.onSurface.withValues(alpha: 0.75),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
|
@ -212,10 +200,7 @@ class _LibraryItemProgressIndicator extends HookConsumerWidget {
|
|||
}
|
||||
|
||||
class _HeroSectionSubLabelWithIcon extends HookConsumerWidget {
|
||||
const _HeroSectionSubLabelWithIcon({
|
||||
required this.icon,
|
||||
required this.text,
|
||||
});
|
||||
const _HeroSectionSubLabelWithIcon({required this.icon, required this.text});
|
||||
|
||||
final IconData icon;
|
||||
final Widget text;
|
||||
|
|
@ -225,8 +210,10 @@ class _HeroSectionSubLabelWithIcon extends HookConsumerWidget {
|
|||
final themeData = Theme.of(context);
|
||||
final useFontAwesome =
|
||||
icon.runtimeType == FontAwesomeIcons.book.runtimeType;
|
||||
final useMaterialThemeOnItemPage =
|
||||
ref.watch(appSettingsProvider).themeSettings.useMaterialThemeOnItemPage;
|
||||
final useMaterialThemeOnItemPage = ref
|
||||
.watch(appSettingsProvider)
|
||||
.themeSettings
|
||||
.useMaterialThemeOnItemPage;
|
||||
final color = useMaterialThemeOnItemPage
|
||||
? themeData.colorScheme.primary
|
||||
: themeData.colorScheme.onSurface.withValues(alpha: 0.75);
|
||||
|
|
@ -237,20 +224,10 @@ class _HeroSectionSubLabelWithIcon extends HookConsumerWidget {
|
|||
Container(
|
||||
margin: const EdgeInsets.only(right: 8, top: 2),
|
||||
child: useFontAwesome
|
||||
? FaIcon(
|
||||
icon,
|
||||
size: 16,
|
||||
color: color,
|
||||
)
|
||||
: Icon(
|
||||
icon,
|
||||
size: 16,
|
||||
color: color,
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: text,
|
||||
? FaIcon(icon, size: 16, color: color)
|
||||
: Icon(icon, size: 16, color: color),
|
||||
),
|
||||
Expanded(child: text),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
|
@ -338,9 +315,7 @@ class _BookNarrators extends StatelessWidget {
|
|||
}
|
||||
|
||||
class _BookCover extends HookConsumerWidget {
|
||||
const _BookCover({
|
||||
required this.itemId,
|
||||
});
|
||||
const _BookCover({required this.itemId});
|
||||
|
||||
final String itemId;
|
||||
|
||||
|
|
@ -358,11 +333,12 @@ class _BookCover extends HookConsumerWidget {
|
|||
themeOfLibraryItemProvider(
|
||||
itemId,
|
||||
brightness: Theme.of(context).brightness,
|
||||
highContrast: themeSettings.highContrast ||
|
||||
highContrast:
|
||||
themeSettings.highContrast ||
|
||||
MediaQuery.of(context).highContrast,
|
||||
),
|
||||
)
|
||||
.valueOrNull;
|
||||
.value;
|
||||
}
|
||||
|
||||
return ThemeSwitcher(
|
||||
|
|
@ -391,15 +367,10 @@ class _BookCover extends HookConsumerWidget {
|
|||
return const Icon(Icons.error);
|
||||
}
|
||||
|
||||
return Image.memory(
|
||||
image,
|
||||
fit: BoxFit.cover,
|
||||
);
|
||||
return Image.memory(image, fit: BoxFit.cover);
|
||||
},
|
||||
loading: () {
|
||||
return const Center(
|
||||
child: BookCoverSkeleton(),
|
||||
);
|
||||
return const Center(child: BookCoverSkeleton());
|
||||
},
|
||||
error: (error, stack) {
|
||||
return const Center(child: Icon(Icons.error));
|
||||
|
|
@ -411,10 +382,7 @@ class _BookCover extends HookConsumerWidget {
|
|||
}
|
||||
|
||||
class _BookTitle extends StatelessWidget {
|
||||
const _BookTitle({
|
||||
required this.extraMap,
|
||||
required this.itemBookMetadata,
|
||||
});
|
||||
const _BookTitle({required this.extraMap, required this.itemBookMetadata});
|
||||
|
||||
final LibraryItemExtras? extraMap;
|
||||
final shelfsdk.BookMetadataExpanded? itemBookMetadata;
|
||||
|
|
@ -426,7 +394,8 @@ class _BookTitle extends StatelessWidget {
|
|||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Hero(
|
||||
tag: HeroTagPrefixes.bookTitle +
|
||||
tag:
|
||||
HeroTagPrefixes.bookTitle +
|
||||
// itemId +
|
||||
(extraMap?.heroTagSuffix ?? ''),
|
||||
child: Text(
|
||||
|
|
|
|||
|
|
@ -4,16 +4,13 @@ import 'package:vaani/api/library_item_provider.dart';
|
|||
import 'package:vaani/shared/extensions/model_conversions.dart';
|
||||
|
||||
class LibraryItemMetadata extends HookConsumerWidget {
|
||||
const LibraryItemMetadata({
|
||||
super.key,
|
||||
required this.id,
|
||||
});
|
||||
const LibraryItemMetadata({super.key, required this.id});
|
||||
|
||||
final String id;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final item = ref.watch(libraryItemProvider(id)).valueOrNull;
|
||||
final item = ref.watch(libraryItemProvider(id)).value;
|
||||
|
||||
/// formats the duration of the book as `10h 30m`
|
||||
///
|
||||
|
|
@ -72,7 +69,8 @@ class LibraryItemMetadata extends HookConsumerWidget {
|
|||
),
|
||||
_MetadataItem(
|
||||
title: 'Published',
|
||||
value: itemBookMetadata?.publishedDate ??
|
||||
value:
|
||||
itemBookMetadata?.publishedDate ??
|
||||
itemBookMetadata?.publishedYear ??
|
||||
'Unknown',
|
||||
),
|
||||
|
|
@ -87,22 +85,18 @@ class LibraryItemMetadata extends HookConsumerWidget {
|
|||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
// alternate between metadata and vertical divider
|
||||
children: List.generate(
|
||||
children.length * 2 - 1,
|
||||
(index) {
|
||||
if (index.isEven) {
|
||||
return children[index ~/ 2];
|
||||
}
|
||||
return VerticalDivider(
|
||||
indent: 6,
|
||||
endIndent: 6,
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.onSurface
|
||||
.withValues(alpha: 0.6),
|
||||
);
|
||||
},
|
||||
),
|
||||
children: List.generate(children.length * 2 - 1, (index) {
|
||||
if (index.isEven) {
|
||||
return children[index ~/ 2];
|
||||
}
|
||||
return VerticalDivider(
|
||||
indent: 6,
|
||||
endIndent: 6,
|
||||
color: Theme.of(
|
||||
context,
|
||||
).colorScheme.onSurface.withValues(alpha: 0.6),
|
||||
);
|
||||
}),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
|
@ -111,10 +105,7 @@ class LibraryItemMetadata extends HookConsumerWidget {
|
|||
|
||||
/// key-value pair to display as column
|
||||
class _MetadataItem extends StatelessWidget {
|
||||
const _MetadataItem({
|
||||
required this.title,
|
||||
required this.value,
|
||||
});
|
||||
const _MetadataItem({required this.title, required this.value});
|
||||
|
||||
final String title;
|
||||
final String value;
|
||||
|
|
|
|||
|
|
@ -16,49 +16,43 @@ import 'library_item_hero_section.dart';
|
|||
import 'library_item_metadata.dart';
|
||||
|
||||
class LibraryItemPage extends HookConsumerWidget {
|
||||
const LibraryItemPage({
|
||||
super.key,
|
||||
required this.itemId,
|
||||
this.extra,
|
||||
});
|
||||
const LibraryItemPage({super.key, required this.itemId, this.extra});
|
||||
|
||||
final String itemId;
|
||||
final Object? extra;
|
||||
static const double _showFabThreshold = 300.0;
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final additionalItemData =
|
||||
extra is LibraryItemExtras ? extra as LibraryItemExtras : null;
|
||||
final additionalItemData = extra is LibraryItemExtras
|
||||
? extra as LibraryItemExtras
|
||||
: null;
|
||||
final scrollController = useScrollController();
|
||||
final showFab = useState(false);
|
||||
|
||||
// Effect to listen to scroll changes and update FAB visibility
|
||||
useEffect(
|
||||
() {
|
||||
void listener() {
|
||||
if (!scrollController.hasClients) {
|
||||
return; // Ensure controller is attached
|
||||
}
|
||||
final shouldShow = scrollController.offset > _showFabThreshold;
|
||||
// Update state only if it changes and widget is still mounted
|
||||
if (showFab.value != shouldShow && context.mounted) {
|
||||
showFab.value = shouldShow;
|
||||
}
|
||||
useEffect(() {
|
||||
void listener() {
|
||||
if (!scrollController.hasClients) {
|
||||
return; // Ensure controller is attached
|
||||
}
|
||||
final shouldShow = scrollController.offset > _showFabThreshold;
|
||||
// Update state only if it changes and widget is still mounted
|
||||
if (showFab.value != shouldShow && context.mounted) {
|
||||
showFab.value = shouldShow;
|
||||
}
|
||||
}
|
||||
|
||||
scrollController.addListener(listener);
|
||||
// Initial check in case the view starts scrolled (less likely but safe)
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
if (scrollController.hasClients && context.mounted) {
|
||||
listener();
|
||||
}
|
||||
});
|
||||
scrollController.addListener(listener);
|
||||
// Initial check in case the view starts scrolled (less likely but safe)
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
if (scrollController.hasClients && context.mounted) {
|
||||
listener();
|
||||
}
|
||||
});
|
||||
|
||||
// Cleanup: remove the listener when the widget is disposed
|
||||
return () => scrollController.removeListener(listener);
|
||||
},
|
||||
[scrollController],
|
||||
); // Re-run effect if scrollController changes
|
||||
// Cleanup: remove the listener when the widget is disposed
|
||||
return () => scrollController.removeListener(listener);
|
||||
}, [scrollController]); // Re-run effect if scrollController changes
|
||||
|
||||
// --- FAB Scroll-to-Top Logic ---
|
||||
void scrollToTop() {
|
||||
|
|
@ -82,10 +76,7 @@ class LibraryItemPage extends HookConsumerWidget {
|
|||
transitionBuilder: (Widget child, Animation<double> animation) {
|
||||
return ScaleTransition(
|
||||
scale: animation,
|
||||
child: FadeTransition(
|
||||
opacity: animation,
|
||||
child: child,
|
||||
),
|
||||
child: FadeTransition(opacity: animation, child: child),
|
||||
);
|
||||
},
|
||||
child: showFab.value
|
||||
|
|
@ -96,9 +87,7 @@ class LibraryItemPage extends HookConsumerWidget {
|
|||
tooltip: 'Scroll to top',
|
||||
child: const Icon(Icons.arrow_upward),
|
||||
)
|
||||
: const SizedBox.shrink(
|
||||
key: ValueKey('fab-empty'),
|
||||
),
|
||||
: const SizedBox.shrink(key: ValueKey('fab-empty')),
|
||||
),
|
||||
body: CustomScrollView(
|
||||
controller: scrollController,
|
||||
|
|
@ -115,17 +104,11 @@ class LibraryItemPage extends HookConsumerWidget {
|
|||
),
|
||||
),
|
||||
// a horizontal display with dividers of metadata
|
||||
SliverToBoxAdapter(
|
||||
child: LibraryItemMetadata(id: itemId),
|
||||
),
|
||||
SliverToBoxAdapter(child: LibraryItemMetadata(id: itemId)),
|
||||
// a row of actions like play, download, share, etc
|
||||
SliverToBoxAdapter(
|
||||
child: LibraryItemActions(id: itemId),
|
||||
),
|
||||
SliverToBoxAdapter(child: LibraryItemActions(id: itemId)),
|
||||
// a expandable section for book description
|
||||
SliverToBoxAdapter(
|
||||
child: LibraryItemDescription(id: itemId),
|
||||
),
|
||||
SliverToBoxAdapter(child: LibraryItemDescription(id: itemId)),
|
||||
// a padding at the bottom to make sure the last item is not hidden by mini player
|
||||
const SliverToBoxAdapter(child: MiniPlayerBottomPadding()),
|
||||
],
|
||||
|
|
@ -137,15 +120,12 @@ class LibraryItemPage extends HookConsumerWidget {
|
|||
}
|
||||
|
||||
class LibraryItemDescription extends HookConsumerWidget {
|
||||
const LibraryItemDescription({
|
||||
super.key,
|
||||
required this.id,
|
||||
});
|
||||
const LibraryItemDescription({super.key, required this.id});
|
||||
|
||||
final String id;
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final item = ref.watch(libraryItemProvider(id)).valueOrNull;
|
||||
final item = ref.watch(libraryItemProvider(id)).value;
|
||||
if (item == null) {
|
||||
return const SizedBox();
|
||||
}
|
||||
|
|
@ -160,16 +140,21 @@ class LibraryItemDescription extends HookConsumerWidget {
|
|||
double calculateWidth(
|
||||
BuildContext context,
|
||||
BoxConstraints constraints, {
|
||||
|
||||
/// width ratio of the cover image to the available width
|
||||
double widthRatio = 0.4,
|
||||
|
||||
/// height ratio of the cover image to the available height
|
||||
double maxHeightToUse = 0.25,
|
||||
}) {
|
||||
final availHeight =
|
||||
min(constraints.maxHeight, MediaQuery.of(context).size.height);
|
||||
final availWidth =
|
||||
min(constraints.maxWidth, MediaQuery.of(context).size.width);
|
||||
final availHeight = min(
|
||||
constraints.maxHeight,
|
||||
MediaQuery.of(context).size.height,
|
||||
);
|
||||
final availWidth = min(
|
||||
constraints.maxWidth,
|
||||
MediaQuery.of(context).size.width,
|
||||
);
|
||||
|
||||
// make the width widthRatio of the available width
|
||||
var width = availWidth * widthRatio;
|
||||
|
|
|
|||
|
|
@ -17,32 +17,30 @@ class LibraryItemSliverAppBar extends HookConsumerWidget {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final item = ref.watch(libraryItemProvider(id)).valueOrNull;
|
||||
final item = ref.watch(libraryItemProvider(id)).value;
|
||||
|
||||
final showTitle = useState(false);
|
||||
|
||||
useEffect(
|
||||
() {
|
||||
void listener() {
|
||||
final shouldShow = scrollController.hasClients &&
|
||||
scrollController.offset > _showTitleThreshold;
|
||||
if (showTitle.value != shouldShow) {
|
||||
showTitle.value = shouldShow;
|
||||
}
|
||||
useEffect(() {
|
||||
void listener() {
|
||||
final shouldShow =
|
||||
scrollController.hasClients &&
|
||||
scrollController.offset > _showTitleThreshold;
|
||||
if (showTitle.value != shouldShow) {
|
||||
showTitle.value = shouldShow;
|
||||
}
|
||||
}
|
||||
|
||||
scrollController.addListener(listener);
|
||||
// Trigger listener once initially in case the view starts scrolled
|
||||
// (though unlikely for this specific use case, it's good practice)
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
if (scrollController.hasClients) {
|
||||
listener();
|
||||
}
|
||||
});
|
||||
return () => scrollController.removeListener(listener);
|
||||
},
|
||||
[scrollController],
|
||||
);
|
||||
scrollController.addListener(listener);
|
||||
// Trigger listener once initially in case the view starts scrolled
|
||||
// (though unlikely for this specific use case, it's good practice)
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
if (scrollController.hasClients) {
|
||||
listener();
|
||||
}
|
||||
});
|
||||
return () => scrollController.removeListener(listener);
|
||||
}, [scrollController]);
|
||||
|
||||
return SliverAppBar(
|
||||
elevation: 0,
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ class LibraryBrowserPage extends HookConsumerWidget {
|
|||
const LibraryBrowserPage({super.key});
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final currentLibrary = ref.watch(currentLibraryProvider).valueOrNull;
|
||||
final currentLibrary = ref.watch(currentLibraryProvider).value;
|
||||
|
||||
// Determine the icon to use, with a fallback
|
||||
final IconData libraryIconData =
|
||||
|
|
@ -41,43 +41,41 @@ class LibraryBrowserPage extends HookConsumerWidget {
|
|||
title: Text(appBarTitle),
|
||||
),
|
||||
SliverList(
|
||||
delegate: SliverChildListDelegate(
|
||||
[
|
||||
ListTile(
|
||||
title: const Text('Authors'),
|
||||
leading: const Icon(Icons.person),
|
||||
trailing: const Icon(Icons.chevron_right),
|
||||
onTap: () {
|
||||
showNotImplementedToast(context);
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: const Text('Genres'),
|
||||
leading: const Icon(Icons.category),
|
||||
trailing: const Icon(Icons.chevron_right),
|
||||
onTap: () {
|
||||
showNotImplementedToast(context);
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: const Text('Series'),
|
||||
leading: const Icon(Icons.list),
|
||||
trailing: const Icon(Icons.chevron_right),
|
||||
onTap: () {
|
||||
showNotImplementedToast(context);
|
||||
},
|
||||
),
|
||||
// Downloads
|
||||
ListTile(
|
||||
title: const Text('Downloads'),
|
||||
leading: const Icon(Icons.download),
|
||||
trailing: const Icon(Icons.chevron_right),
|
||||
onTap: () {
|
||||
GoRouter.of(context).pushNamed(Routes.downloads.name);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
delegate: SliverChildListDelegate([
|
||||
ListTile(
|
||||
title: const Text('Authors'),
|
||||
leading: const Icon(Icons.person),
|
||||
trailing: const Icon(Icons.chevron_right),
|
||||
onTap: () {
|
||||
showNotImplementedToast(context);
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: const Text('Genres'),
|
||||
leading: const Icon(Icons.category),
|
||||
trailing: const Icon(Icons.chevron_right),
|
||||
onTap: () {
|
||||
showNotImplementedToast(context);
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: const Text('Series'),
|
||||
leading: const Icon(Icons.list),
|
||||
trailing: const Icon(Icons.chevron_right),
|
||||
onTap: () {
|
||||
showNotImplementedToast(context);
|
||||
},
|
||||
),
|
||||
// Downloads
|
||||
ListTile(
|
||||
title: const Text('Downloads'),
|
||||
leading: const Icon(Icons.download),
|
||||
trailing: const Icon(Icons.chevron_right),
|
||||
onTap: () {
|
||||
GoRouter.of(context).pushNamed(Routes.downloads.name);
|
||||
},
|
||||
),
|
||||
]),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
|
|
|||
|
|
@ -59,8 +59,10 @@ String generateZipFileName() {
|
|||
}
|
||||
|
||||
Level parseLevel(String level) {
|
||||
return Level.LEVELS
|
||||
.firstWhere((l) => l.name == level, orElse: () => Level.ALL);
|
||||
return Level.LEVELS.firstWhere(
|
||||
(l) => l.name == level,
|
||||
orElse: () => Level.ALL,
|
||||
);
|
||||
}
|
||||
|
||||
LogRecord parseLogLine(String line) {
|
||||
|
|
|
|||
|
|
@ -6,20 +6,48 @@ part of 'logs_provider.dart';
|
|||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
|
||||
@ProviderFor(Logs)
|
||||
final logsProvider = LogsProvider._();
|
||||
|
||||
final class LogsProvider extends $AsyncNotifierProvider<Logs, List<LogRecord>> {
|
||||
LogsProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
retry: null,
|
||||
name: r'logsProvider',
|
||||
isAutoDispose: true,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$logsHash();
|
||||
|
||||
@$internal
|
||||
@override
|
||||
Logs create() => Logs();
|
||||
}
|
||||
|
||||
String _$logsHash() => r'aa9d3d56586cba6ddf69615320ea605d071ea5e2';
|
||||
|
||||
/// See also [Logs].
|
||||
@ProviderFor(Logs)
|
||||
final logsProvider =
|
||||
AutoDisposeAsyncNotifierProvider<Logs, List<LogRecord>>.internal(
|
||||
Logs.new,
|
||||
name: r'logsProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product') ? null : _$logsHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
typedef _$Logs = AutoDisposeAsyncNotifier<List<LogRecord>>;
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package
|
||||
abstract class _$Logs extends $AsyncNotifier<List<LogRecord>> {
|
||||
FutureOr<List<LogRecord>> build();
|
||||
@$mustCallSuper
|
||||
@override
|
||||
void runBuild() {
|
||||
final ref = this.ref as $Ref<AsyncValue<List<LogRecord>>, List<LogRecord>>;
|
||||
final element =
|
||||
ref.element
|
||||
as $ClassProviderElement<
|
||||
AnyNotifier<AsyncValue<List<LogRecord>>, List<LogRecord>>,
|
||||
AsyncValue<List<LogRecord>>,
|
||||
Object?,
|
||||
Object?
|
||||
>;
|
||||
element.handleCreate(ref, build);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,8 +54,9 @@ class LogsPage extends HookConsumerWidget {
|
|||
icon: const Icon(Icons.share),
|
||||
onPressed: () async {
|
||||
appLogger.info('Preparing logs for sharing');
|
||||
final zipLogFilePath =
|
||||
await ref.read(logsProvider.notifier).getZipFilePath();
|
||||
final zipLogFilePath = await ref
|
||||
.read(logsProvider.notifier)
|
||||
.getZipFilePath();
|
||||
|
||||
// submit logs
|
||||
final result = await Share.shareXFiles([XFile(zipLogFilePath)]);
|
||||
|
|
@ -169,7 +170,6 @@ class LogsPage extends HookConsumerWidget {
|
|||
children: [
|
||||
// a filter for log levels, loggers, and search
|
||||
// TODO: implement filters and search
|
||||
|
||||
Expanded(
|
||||
child: logs.when(
|
||||
data: (logRecords) {
|
||||
|
|
@ -243,9 +243,7 @@ class LogRecordTile extends StatelessWidget {
|
|||
style: const TextStyle(fontStyle: FontStyle.italic),
|
||||
),
|
||||
const TextSpan(text: '\n\n'),
|
||||
TextSpan(
|
||||
text: logRecord.message,
|
||||
),
|
||||
TextSpan(text: logRecord.message),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import 'package:freezed_annotation/freezed_annotation.dart';
|
|||
part 'flow.freezed.dart';
|
||||
|
||||
@freezed
|
||||
class Flow with _$Flow {
|
||||
sealed class Flow with _$Flow {
|
||||
const factory Flow({
|
||||
required Uri serverUri,
|
||||
required String state,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
// coverage:ignore-file
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// coverage:ignore-file
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
|
||||
|
||||
|
|
@ -9,241 +9,272 @@ part of 'flow.dart';
|
|||
// FreezedGenerator
|
||||
// **************************************************************************
|
||||
|
||||
// dart format off
|
||||
T _$identity<T>(T value) => value;
|
||||
|
||||
final _privateConstructorUsedError = UnsupportedError(
|
||||
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models');
|
||||
|
||||
/// @nodoc
|
||||
mixin _$Flow {
|
||||
Uri get serverUri => throw _privateConstructorUsedError;
|
||||
String get state => throw _privateConstructorUsedError;
|
||||
String get verifier => throw _privateConstructorUsedError;
|
||||
Cookie get cookie => throw _privateConstructorUsedError;
|
||||
bool get isFlowComplete => throw _privateConstructorUsedError;
|
||||
String? get authToken => throw _privateConstructorUsedError;
|
||||
|
||||
/// Create a copy of Flow
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
$FlowCopyWith<Flow> get copyWith => throw _privateConstructorUsedError;
|
||||
Uri get serverUri; String get state; String get verifier; Cookie get cookie; bool get isFlowComplete; String? get authToken;
|
||||
/// Create a copy of Flow
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
$FlowCopyWith<Flow> get copyWith => _$FlowCopyWithImpl<Flow>(this as Flow, _$identity);
|
||||
|
||||
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is Flow&&(identical(other.serverUri, serverUri) || other.serverUri == serverUri)&&(identical(other.state, state) || other.state == state)&&(identical(other.verifier, verifier) || other.verifier == verifier)&&(identical(other.cookie, cookie) || other.cookie == cookie)&&(identical(other.isFlowComplete, isFlowComplete) || other.isFlowComplete == isFlowComplete)&&(identical(other.authToken, authToken) || other.authToken == authToken));
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,serverUri,state,verifier,cookie,isFlowComplete,authToken);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'Flow(serverUri: $serverUri, state: $state, verifier: $verifier, cookie: $cookie, isFlowComplete: $isFlowComplete, authToken: $authToken)';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $FlowCopyWith<$Res> {
|
||||
factory $FlowCopyWith(Flow value, $Res Function(Flow) then) =
|
||||
_$FlowCopyWithImpl<$Res, Flow>;
|
||||
@useResult
|
||||
$Res call(
|
||||
{Uri serverUri,
|
||||
String state,
|
||||
String verifier,
|
||||
Cookie cookie,
|
||||
bool isFlowComplete,
|
||||
String? authToken});
|
||||
}
|
||||
abstract mixin class $FlowCopyWith<$Res> {
|
||||
factory $FlowCopyWith(Flow value, $Res Function(Flow) _then) = _$FlowCopyWithImpl;
|
||||
@useResult
|
||||
$Res call({
|
||||
Uri serverUri, String state, String verifier, Cookie cookie, bool isFlowComplete, String? authToken
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
/// @nodoc
|
||||
class _$FlowCopyWithImpl<$Res, $Val extends Flow>
|
||||
class _$FlowCopyWithImpl<$Res>
|
||||
implements $FlowCopyWith<$Res> {
|
||||
_$FlowCopyWithImpl(this._value, this._then);
|
||||
_$FlowCopyWithImpl(this._self, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
final Flow _self;
|
||||
final $Res Function(Flow) _then;
|
||||
|
||||
/// Create a copy of Flow
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? serverUri = null,
|
||||
Object? state = null,
|
||||
Object? verifier = null,
|
||||
Object? cookie = null,
|
||||
Object? isFlowComplete = null,
|
||||
Object? authToken = freezed,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
serverUri: null == serverUri
|
||||
? _value.serverUri
|
||||
: serverUri // ignore: cast_nullable_to_non_nullable
|
||||
as Uri,
|
||||
state: null == state
|
||||
? _value.state
|
||||
: state // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
verifier: null == verifier
|
||||
? _value.verifier
|
||||
: verifier // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
cookie: null == cookie
|
||||
? _value.cookie
|
||||
: cookie // ignore: cast_nullable_to_non_nullable
|
||||
as Cookie,
|
||||
isFlowComplete: null == isFlowComplete
|
||||
? _value.isFlowComplete
|
||||
: isFlowComplete // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
authToken: freezed == authToken
|
||||
? _value.authToken
|
||||
: authToken // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
) as $Val);
|
||||
}
|
||||
/// Create a copy of Flow
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? serverUri = null,Object? state = null,Object? verifier = null,Object? cookie = null,Object? isFlowComplete = null,Object? authToken = freezed,}) {
|
||||
return _then(_self.copyWith(
|
||||
serverUri: null == serverUri ? _self.serverUri : serverUri // ignore: cast_nullable_to_non_nullable
|
||||
as Uri,state: null == state ? _self.state : state // ignore: cast_nullable_to_non_nullable
|
||||
as String,verifier: null == verifier ? _self.verifier : verifier // ignore: cast_nullable_to_non_nullable
|
||||
as String,cookie: null == cookie ? _self.cookie : cookie // ignore: cast_nullable_to_non_nullable
|
||||
as Cookie,isFlowComplete: null == isFlowComplete ? _self.isFlowComplete : isFlowComplete // ignore: cast_nullable_to_non_nullable
|
||||
as bool,authToken: freezed == authToken ? _self.authToken : authToken // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
));
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$FlowImplCopyWith<$Res> implements $FlowCopyWith<$Res> {
|
||||
factory _$$FlowImplCopyWith(
|
||||
_$FlowImpl value, $Res Function(_$FlowImpl) then) =
|
||||
__$$FlowImplCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call(
|
||||
{Uri serverUri,
|
||||
String state,
|
||||
String verifier,
|
||||
Cookie cookie,
|
||||
bool isFlowComplete,
|
||||
String? authToken});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$FlowImplCopyWithImpl<$Res>
|
||||
extends _$FlowCopyWithImpl<$Res, _$FlowImpl>
|
||||
implements _$$FlowImplCopyWith<$Res> {
|
||||
__$$FlowImplCopyWithImpl(_$FlowImpl _value, $Res Function(_$FlowImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of Flow
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? serverUri = null,
|
||||
Object? state = null,
|
||||
Object? verifier = null,
|
||||
Object? cookie = null,
|
||||
Object? isFlowComplete = null,
|
||||
Object? authToken = freezed,
|
||||
}) {
|
||||
return _then(_$FlowImpl(
|
||||
serverUri: null == serverUri
|
||||
? _value.serverUri
|
||||
: serverUri // ignore: cast_nullable_to_non_nullable
|
||||
as Uri,
|
||||
state: null == state
|
||||
? _value.state
|
||||
: state // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
verifier: null == verifier
|
||||
? _value.verifier
|
||||
: verifier // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
cookie: null == cookie
|
||||
? _value.cookie
|
||||
: cookie // ignore: cast_nullable_to_non_nullable
|
||||
as Cookie,
|
||||
isFlowComplete: null == isFlowComplete
|
||||
? _value.isFlowComplete
|
||||
: isFlowComplete // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
authToken: freezed == authToken
|
||||
? _value.authToken
|
||||
: authToken // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
));
|
||||
}
|
||||
/// Adds pattern-matching-related methods to [Flow].
|
||||
extension FlowPatterns on Flow {
|
||||
/// A variant of `map` that fallback to returning `orElse`.
|
||||
///
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case final Subclass value:
|
||||
/// return ...;
|
||||
/// case _:
|
||||
/// return orElse();
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _Flow value)? $default,{required TResult orElse(),}){
|
||||
final _that = this;
|
||||
switch (_that) {
|
||||
case _Flow() when $default != null:
|
||||
return $default(_that);case _:
|
||||
return orElse();
|
||||
|
||||
}
|
||||
}
|
||||
/// A `switch`-like method, using callbacks.
|
||||
///
|
||||
/// Callbacks receives the raw object, upcasted.
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case final Subclass value:
|
||||
/// return ...;
|
||||
/// case final Subclass2 value:
|
||||
/// return ...;
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _Flow value) $default,){
|
||||
final _that = this;
|
||||
switch (_that) {
|
||||
case _Flow():
|
||||
return $default(_that);}
|
||||
}
|
||||
/// A variant of `map` that fallback to returning `null`.
|
||||
///
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case final Subclass value:
|
||||
/// return ...;
|
||||
/// case _:
|
||||
/// return null;
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _Flow value)? $default,){
|
||||
final _that = this;
|
||||
switch (_that) {
|
||||
case _Flow() when $default != null:
|
||||
return $default(_that);case _:
|
||||
return null;
|
||||
|
||||
}
|
||||
}
|
||||
/// A variant of `when` that fallback to an `orElse` callback.
|
||||
///
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case Subclass(:final field):
|
||||
/// return ...;
|
||||
/// case _:
|
||||
/// return orElse();
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( Uri serverUri, String state, String verifier, Cookie cookie, bool isFlowComplete, String? authToken)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
switch (_that) {
|
||||
case _Flow() when $default != null:
|
||||
return $default(_that.serverUri,_that.state,_that.verifier,_that.cookie,_that.isFlowComplete,_that.authToken);case _:
|
||||
return orElse();
|
||||
|
||||
}
|
||||
}
|
||||
/// A `switch`-like method, using callbacks.
|
||||
///
|
||||
/// As opposed to `map`, this offers destructuring.
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case Subclass(:final field):
|
||||
/// return ...;
|
||||
/// case Subclass2(:final field2):
|
||||
/// return ...;
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( Uri serverUri, String state, String verifier, Cookie cookie, bool isFlowComplete, String? authToken) $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _Flow():
|
||||
return $default(_that.serverUri,_that.state,_that.verifier,_that.cookie,_that.isFlowComplete,_that.authToken);}
|
||||
}
|
||||
/// A variant of `when` that fallback to returning `null`
|
||||
///
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case Subclass(:final field):
|
||||
/// return ...;
|
||||
/// case _:
|
||||
/// return null;
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( Uri serverUri, String state, String verifier, Cookie cookie, bool isFlowComplete, String? authToken)? $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _Flow() when $default != null:
|
||||
return $default(_that.serverUri,_that.state,_that.verifier,_that.cookie,_that.isFlowComplete,_that.authToken);case _:
|
||||
return null;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$FlowImpl implements _Flow {
|
||||
const _$FlowImpl(
|
||||
{required this.serverUri,
|
||||
required this.state,
|
||||
required this.verifier,
|
||||
required this.cookie,
|
||||
this.isFlowComplete = false,
|
||||
this.authToken});
|
||||
|
||||
@override
|
||||
final Uri serverUri;
|
||||
@override
|
||||
final String state;
|
||||
@override
|
||||
final String verifier;
|
||||
@override
|
||||
final Cookie cookie;
|
||||
@override
|
||||
@JsonKey()
|
||||
final bool isFlowComplete;
|
||||
@override
|
||||
final String? authToken;
|
||||
class _Flow implements Flow {
|
||||
const _Flow({required this.serverUri, required this.state, required this.verifier, required this.cookie, this.isFlowComplete = false, this.authToken});
|
||||
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'Flow(serverUri: $serverUri, state: $state, verifier: $verifier, cookie: $cookie, isFlowComplete: $isFlowComplete, authToken: $authToken)';
|
||||
}
|
||||
@override final Uri serverUri;
|
||||
@override final String state;
|
||||
@override final String verifier;
|
||||
@override final Cookie cookie;
|
||||
@override@JsonKey() final bool isFlowComplete;
|
||||
@override final String? authToken;
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$FlowImpl &&
|
||||
(identical(other.serverUri, serverUri) ||
|
||||
other.serverUri == serverUri) &&
|
||||
(identical(other.state, state) || other.state == state) &&
|
||||
(identical(other.verifier, verifier) ||
|
||||
other.verifier == verifier) &&
|
||||
(identical(other.cookie, cookie) || other.cookie == cookie) &&
|
||||
(identical(other.isFlowComplete, isFlowComplete) ||
|
||||
other.isFlowComplete == isFlowComplete) &&
|
||||
(identical(other.authToken, authToken) ||
|
||||
other.authToken == authToken));
|
||||
}
|
||||
/// Create a copy of Flow
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
_$FlowCopyWith<_Flow> get copyWith => __$FlowCopyWithImpl<_Flow>(this, _$identity);
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, serverUri, state, verifier,
|
||||
cookie, isFlowComplete, authToken);
|
||||
|
||||
/// Create a copy of Flow
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$FlowImplCopyWith<_$FlowImpl> get copyWith =>
|
||||
__$$FlowImplCopyWithImpl<_$FlowImpl>(this, _$identity);
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _Flow&&(identical(other.serverUri, serverUri) || other.serverUri == serverUri)&&(identical(other.state, state) || other.state == state)&&(identical(other.verifier, verifier) || other.verifier == verifier)&&(identical(other.cookie, cookie) || other.cookie == cookie)&&(identical(other.isFlowComplete, isFlowComplete) || other.isFlowComplete == isFlowComplete)&&(identical(other.authToken, authToken) || other.authToken == authToken));
|
||||
}
|
||||
|
||||
abstract class _Flow implements Flow {
|
||||
const factory _Flow(
|
||||
{required final Uri serverUri,
|
||||
required final String state,
|
||||
required final String verifier,
|
||||
required final Cookie cookie,
|
||||
final bool isFlowComplete,
|
||||
final String? authToken}) = _$FlowImpl;
|
||||
|
||||
@override
|
||||
Uri get serverUri;
|
||||
@override
|
||||
String get state;
|
||||
@override
|
||||
String get verifier;
|
||||
@override
|
||||
Cookie get cookie;
|
||||
@override
|
||||
bool get isFlowComplete;
|
||||
@override
|
||||
String? get authToken;
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,serverUri,state,verifier,cookie,isFlowComplete,authToken);
|
||||
|
||||
/// Create a copy of Flow
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$FlowImplCopyWith<_$FlowImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
@override
|
||||
String toString() {
|
||||
return 'Flow(serverUri: $serverUri, state: $state, verifier: $verifier, cookie: $cookie, isFlowComplete: $isFlowComplete, authToken: $authToken)';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class _$FlowCopyWith<$Res> implements $FlowCopyWith<$Res> {
|
||||
factory _$FlowCopyWith(_Flow value, $Res Function(_Flow) _then) = __$FlowCopyWithImpl;
|
||||
@override @useResult
|
||||
$Res call({
|
||||
Uri serverUri, String state, String verifier, Cookie cookie, bool isFlowComplete, String? authToken
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
/// @nodoc
|
||||
class __$FlowCopyWithImpl<$Res>
|
||||
implements _$FlowCopyWith<$Res> {
|
||||
__$FlowCopyWithImpl(this._self, this._then);
|
||||
|
||||
final _Flow _self;
|
||||
final $Res Function(_Flow) _then;
|
||||
|
||||
/// Create a copy of Flow
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? serverUri = null,Object? state = null,Object? verifier = null,Object? cookie = null,Object? isFlowComplete = null,Object? authToken = freezed,}) {
|
||||
return _then(_Flow(
|
||||
serverUri: null == serverUri ? _self.serverUri : serverUri // ignore: cast_nullable_to_non_nullable
|
||||
as Uri,state: null == state ? _self.state : state // ignore: cast_nullable_to_non_nullable
|
||||
as String,verifier: null == verifier ? _self.verifier : verifier // ignore: cast_nullable_to_non_nullable
|
||||
as String,cookie: null == cookie ? _self.cookie : cookie // ignore: cast_nullable_to_non_nullable
|
||||
as Cookie,isFlowComplete: null == isFlowComplete ? _self.isFlowComplete : isFlowComplete // ignore: cast_nullable_to_non_nullable
|
||||
as bool,authToken: freezed == authToken ? _self.authToken : authToken // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// dart format on
|
||||
|
|
|
|||
|
|
@ -53,8 +53,10 @@ class OauthFlows extends _$OauthFlows {
|
|||
}
|
||||
state = {
|
||||
...state,
|
||||
oauthState: state[oauthState]!
|
||||
.copyWith(isFlowComplete: true, authToken: authToken),
|
||||
oauthState: state[oauthState]!.copyWith(
|
||||
isFlowComplete: true,
|
||||
authToken: authToken,
|
||||
),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,221 +6,167 @@ part of 'oauth_provider.dart';
|
|||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$loginInExchangeForCodeHash() =>
|
||||
r'bfc3945529048a0f536052fd5579b76457560fcd';
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
_SystemHash._();
|
||||
@ProviderFor(OauthFlows)
|
||||
final oauthFlowsProvider = OauthFlowsProvider._();
|
||||
|
||||
static int combine(int hash, int value) {
|
||||
// ignore: parameter_assignments
|
||||
hash = 0x1fffffff & (hash + value);
|
||||
// ignore: parameter_assignments
|
||||
hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
|
||||
return hash ^ (hash >> 6);
|
||||
}
|
||||
|
||||
static int finish(int hash) {
|
||||
// ignore: parameter_assignments
|
||||
hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
|
||||
// ignore: parameter_assignments
|
||||
hash = hash ^ (hash >> 11);
|
||||
return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
|
||||
}
|
||||
}
|
||||
|
||||
/// the code returned by the server in exchange for the verifier
|
||||
///
|
||||
/// Copied from [loginInExchangeForCode].
|
||||
@ProviderFor(loginInExchangeForCode)
|
||||
const loginInExchangeForCodeProvider = LoginInExchangeForCodeFamily();
|
||||
|
||||
/// the code returned by the server in exchange for the verifier
|
||||
///
|
||||
/// Copied from [loginInExchangeForCode].
|
||||
class LoginInExchangeForCodeFamily extends Family<AsyncValue<String?>> {
|
||||
/// the code returned by the server in exchange for the verifier
|
||||
///
|
||||
/// Copied from [loginInExchangeForCode].
|
||||
const LoginInExchangeForCodeFamily();
|
||||
|
||||
/// the code returned by the server in exchange for the verifier
|
||||
///
|
||||
/// Copied from [loginInExchangeForCode].
|
||||
LoginInExchangeForCodeProvider call({
|
||||
required String oauthState,
|
||||
required String code,
|
||||
ErrorResponseHandler? responseHandler,
|
||||
}) {
|
||||
return LoginInExchangeForCodeProvider(
|
||||
oauthState: oauthState,
|
||||
code: code,
|
||||
responseHandler: responseHandler,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
LoginInExchangeForCodeProvider getProviderOverride(
|
||||
covariant LoginInExchangeForCodeProvider provider,
|
||||
) {
|
||||
return call(
|
||||
oauthState: provider.oauthState,
|
||||
code: provider.code,
|
||||
responseHandler: provider.responseHandler,
|
||||
);
|
||||
}
|
||||
|
||||
static const Iterable<ProviderOrFamily>? _dependencies = null;
|
||||
|
||||
@override
|
||||
Iterable<ProviderOrFamily>? get dependencies => _dependencies;
|
||||
|
||||
static const Iterable<ProviderOrFamily>? _allTransitiveDependencies = null;
|
||||
|
||||
@override
|
||||
Iterable<ProviderOrFamily>? get allTransitiveDependencies =>
|
||||
_allTransitiveDependencies;
|
||||
|
||||
@override
|
||||
String? get name => r'loginInExchangeForCodeProvider';
|
||||
}
|
||||
|
||||
/// the code returned by the server in exchange for the verifier
|
||||
///
|
||||
/// Copied from [loginInExchangeForCode].
|
||||
class LoginInExchangeForCodeProvider
|
||||
extends AutoDisposeFutureProvider<String?> {
|
||||
/// the code returned by the server in exchange for the verifier
|
||||
///
|
||||
/// Copied from [loginInExchangeForCode].
|
||||
LoginInExchangeForCodeProvider({
|
||||
required String oauthState,
|
||||
required String code,
|
||||
ErrorResponseHandler? responseHandler,
|
||||
}) : this._internal(
|
||||
(ref) => loginInExchangeForCode(
|
||||
ref as LoginInExchangeForCodeRef,
|
||||
oauthState: oauthState,
|
||||
code: code,
|
||||
responseHandler: responseHandler,
|
||||
),
|
||||
from: loginInExchangeForCodeProvider,
|
||||
name: r'loginInExchangeForCodeProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$loginInExchangeForCodeHash,
|
||||
dependencies: LoginInExchangeForCodeFamily._dependencies,
|
||||
allTransitiveDependencies:
|
||||
LoginInExchangeForCodeFamily._allTransitiveDependencies,
|
||||
oauthState: oauthState,
|
||||
code: code,
|
||||
responseHandler: responseHandler,
|
||||
);
|
||||
|
||||
LoginInExchangeForCodeProvider._internal(
|
||||
super._createNotifier, {
|
||||
required super.name,
|
||||
required super.dependencies,
|
||||
required super.allTransitiveDependencies,
|
||||
required super.debugGetCreateSourceHash,
|
||||
required super.from,
|
||||
required this.oauthState,
|
||||
required this.code,
|
||||
required this.responseHandler,
|
||||
}) : super.internal();
|
||||
|
||||
final String oauthState;
|
||||
final String code;
|
||||
final ErrorResponseHandler? responseHandler;
|
||||
|
||||
@override
|
||||
Override overrideWith(
|
||||
FutureOr<String?> Function(LoginInExchangeForCodeRef provider) create,
|
||||
) {
|
||||
return ProviderOverride(
|
||||
origin: this,
|
||||
override: LoginInExchangeForCodeProvider._internal(
|
||||
(ref) => create(ref as LoginInExchangeForCodeRef),
|
||||
from: from,
|
||||
name: null,
|
||||
final class OauthFlowsProvider
|
||||
extends $NotifierProvider<OauthFlows, Map<State, Flow>> {
|
||||
OauthFlowsProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
retry: null,
|
||||
name: r'oauthFlowsProvider',
|
||||
isAutoDispose: false,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
debugGetCreateSourceHash: null,
|
||||
oauthState: oauthState,
|
||||
code: code,
|
||||
responseHandler: responseHandler,
|
||||
),
|
||||
);
|
||||
}
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@override
|
||||
AutoDisposeFutureProviderElement<String?> createElement() {
|
||||
return _LoginInExchangeForCodeProviderElement(this);
|
||||
String debugGetCreateSourceHash() => _$oauthFlowsHash();
|
||||
|
||||
@$internal
|
||||
@override
|
||||
OauthFlows create() => OauthFlows();
|
||||
|
||||
/// {@macro riverpod.override_with_value}
|
||||
Override overrideWithValue(Map<State, Flow> value) {
|
||||
return $ProviderOverride(
|
||||
origin: this,
|
||||
providerOverride: $SyncValueProvider<Map<State, Flow>>(value),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
String _$oauthFlowsHash() => r'4e278baa0bf26f2a10694ca2caadb68dd5b6156f';
|
||||
|
||||
abstract class _$OauthFlows extends $Notifier<Map<State, Flow>> {
|
||||
Map<State, Flow> build();
|
||||
@$mustCallSuper
|
||||
@override
|
||||
void runBuild() {
|
||||
final ref = this.ref as $Ref<Map<State, Flow>, Map<State, Flow>>;
|
||||
final element =
|
||||
ref.element
|
||||
as $ClassProviderElement<
|
||||
AnyNotifier<Map<State, Flow>, Map<State, Flow>>,
|
||||
Map<State, Flow>,
|
||||
Object?,
|
||||
Object?
|
||||
>;
|
||||
element.handleCreate(ref, build);
|
||||
}
|
||||
}
|
||||
|
||||
/// the code returned by the server in exchange for the verifier
|
||||
|
||||
@ProviderFor(loginInExchangeForCode)
|
||||
final loginInExchangeForCodeProvider = LoginInExchangeForCodeFamily._();
|
||||
|
||||
/// the code returned by the server in exchange for the verifier
|
||||
|
||||
final class LoginInExchangeForCodeProvider
|
||||
extends $FunctionalProvider<AsyncValue<String?>, String?, FutureOr<String?>>
|
||||
with $FutureModifier<String?>, $FutureProvider<String?> {
|
||||
/// the code returned by the server in exchange for the verifier
|
||||
LoginInExchangeForCodeProvider._({
|
||||
required LoginInExchangeForCodeFamily super.from,
|
||||
required ({
|
||||
State oauthState,
|
||||
Code code,
|
||||
ErrorResponseHandler? responseHandler,
|
||||
})
|
||||
super.argument,
|
||||
}) : super(
|
||||
retry: null,
|
||||
name: r'loginInExchangeForCodeProvider',
|
||||
isAutoDispose: true,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$loginInExchangeForCodeHash();
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return r'loginInExchangeForCodeProvider'
|
||||
''
|
||||
'$argument';
|
||||
}
|
||||
|
||||
@$internal
|
||||
@override
|
||||
$FutureProviderElement<String?> $createElement($ProviderPointer pointer) =>
|
||||
$FutureProviderElement(pointer);
|
||||
|
||||
@override
|
||||
FutureOr<String?> create(Ref ref) {
|
||||
final argument =
|
||||
this.argument
|
||||
as ({
|
||||
State oauthState,
|
||||
Code code,
|
||||
ErrorResponseHandler? responseHandler,
|
||||
});
|
||||
return loginInExchangeForCode(
|
||||
ref,
|
||||
oauthState: argument.oauthState,
|
||||
code: argument.code,
|
||||
responseHandler: argument.responseHandler,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is LoginInExchangeForCodeProvider &&
|
||||
other.oauthState == oauthState &&
|
||||
other.code == code &&
|
||||
other.responseHandler == responseHandler;
|
||||
other.argument == argument;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
||||
hash = _SystemHash.combine(hash, oauthState.hashCode);
|
||||
hash = _SystemHash.combine(hash, code.hashCode);
|
||||
hash = _SystemHash.combine(hash, responseHandler.hashCode);
|
||||
|
||||
return _SystemHash.finish(hash);
|
||||
return argument.hashCode;
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||
// ignore: unused_element
|
||||
mixin LoginInExchangeForCodeRef on AutoDisposeFutureProviderRef<String?> {
|
||||
/// The parameter `oauthState` of this provider.
|
||||
String get oauthState;
|
||||
String _$loginInExchangeForCodeHash() =>
|
||||
r'bfc3945529048a0f536052fd5579b76457560fcd';
|
||||
|
||||
/// The parameter `code` of this provider.
|
||||
String get code;
|
||||
/// the code returned by the server in exchange for the verifier
|
||||
|
||||
/// The parameter `responseHandler` of this provider.
|
||||
ErrorResponseHandler? get responseHandler;
|
||||
final class LoginInExchangeForCodeFamily extends $Family
|
||||
with
|
||||
$FunctionalFamilyOverride<
|
||||
FutureOr<String?>,
|
||||
({State oauthState, Code code, ErrorResponseHandler? responseHandler})
|
||||
> {
|
||||
LoginInExchangeForCodeFamily._()
|
||||
: super(
|
||||
retry: null,
|
||||
name: r'loginInExchangeForCodeProvider',
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
isAutoDispose: true,
|
||||
);
|
||||
|
||||
/// the code returned by the server in exchange for the verifier
|
||||
|
||||
LoginInExchangeForCodeProvider call({
|
||||
required State oauthState,
|
||||
required Code code,
|
||||
ErrorResponseHandler? responseHandler,
|
||||
}) => LoginInExchangeForCodeProvider._(
|
||||
argument: (
|
||||
oauthState: oauthState,
|
||||
code: code,
|
||||
responseHandler: responseHandler,
|
||||
),
|
||||
from: this,
|
||||
);
|
||||
|
||||
@override
|
||||
String toString() => r'loginInExchangeForCodeProvider';
|
||||
}
|
||||
|
||||
class _LoginInExchangeForCodeProviderElement
|
||||
extends AutoDisposeFutureProviderElement<String?>
|
||||
with LoginInExchangeForCodeRef {
|
||||
_LoginInExchangeForCodeProviderElement(super.provider);
|
||||
|
||||
@override
|
||||
String get oauthState =>
|
||||
(origin as LoginInExchangeForCodeProvider).oauthState;
|
||||
@override
|
||||
String get code => (origin as LoginInExchangeForCodeProvider).code;
|
||||
@override
|
||||
ErrorResponseHandler? get responseHandler =>
|
||||
(origin as LoginInExchangeForCodeProvider).responseHandler;
|
||||
}
|
||||
|
||||
String _$oauthFlowsHash() => r'4e278baa0bf26f2a10694ca2caadb68dd5b6156f';
|
||||
|
||||
/// See also [OauthFlows].
|
||||
@ProviderFor(OauthFlows)
|
||||
final oauthFlowsProvider =
|
||||
NotifierProvider<OauthFlows, Map<State, Flow>>.internal(
|
||||
OauthFlows.new,
|
||||
name: r'oauthFlowsProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product') ? null : _$oauthFlowsHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
typedef _$OauthFlows = Notifier<Map<State, Flow>>;
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package
|
||||
|
|
|
|||
|
|
@ -27,9 +27,7 @@ class CallbackPage extends HookConsumerWidget {
|
|||
|
||||
// check if the state is in the flows
|
||||
if (!flows.containsKey(state)) {
|
||||
return const _SomethingWentWrong(
|
||||
message: 'State not found',
|
||||
);
|
||||
return const _SomethingWentWrong(message: 'State not found');
|
||||
}
|
||||
|
||||
// get the token
|
||||
|
|
@ -45,26 +43,21 @@ class CallbackPage extends HookConsumerWidget {
|
|||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text('Contacting server...\nPlease wait\n\nGot:'
|
||||
'\nState: $state\nCode: $code'),
|
||||
Text(
|
||||
'Contacting server...\nPlease wait\n\nGot:'
|
||||
'\nState: $state\nCode: $code',
|
||||
),
|
||||
loginAuthToken.when(
|
||||
data: (authenticationToken) {
|
||||
if (authenticationToken == null) {
|
||||
handleServerError(
|
||||
context,
|
||||
serverErrorResponse,
|
||||
);
|
||||
handleServerError(context, serverErrorResponse);
|
||||
return const BackToLoginButton();
|
||||
}
|
||||
return Text('Token: $authenticationToken');
|
||||
},
|
||||
loading: () => const CircularProgressIndicator(),
|
||||
error: (error, _) {
|
||||
handleServerError(
|
||||
context,
|
||||
serverErrorResponse,
|
||||
e: error,
|
||||
);
|
||||
handleServerError(context, serverErrorResponse, e: error);
|
||||
return Column(
|
||||
children: [
|
||||
Text('Error with OAuth flow: $error'),
|
||||
|
|
@ -81,9 +74,7 @@ class CallbackPage extends HookConsumerWidget {
|
|||
}
|
||||
|
||||
class BackToLoginButton extends StatelessWidget {
|
||||
const BackToLoginButton({
|
||||
super.key,
|
||||
});
|
||||
const BackToLoginButton({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
|
@ -97,9 +88,7 @@ class BackToLoginButton extends StatelessWidget {
|
|||
}
|
||||
|
||||
class _SomethingWentWrong extends StatelessWidget {
|
||||
const _SomethingWentWrong({
|
||||
this.message = 'Error with OAuth flow',
|
||||
});
|
||||
const _SomethingWentWrong({this.message = 'Error with OAuth flow'});
|
||||
|
||||
final String message;
|
||||
|
||||
|
|
@ -109,10 +98,7 @@ class _SomethingWentWrong extends StatelessWidget {
|
|||
body: Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(message),
|
||||
const BackToLoginButton(),
|
||||
],
|
||||
children: [Text(message), const BackToLoginButton()],
|
||||
),
|
||||
),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -9,9 +9,7 @@ import 'package:vaani/shared/utils.dart';
|
|||
import 'package:vaani/shared/widgets/add_new_server.dart';
|
||||
|
||||
class OnboardingSinglePage extends HookConsumerWidget {
|
||||
const OnboardingSinglePage({
|
||||
super.key,
|
||||
});
|
||||
const OnboardingSinglePage({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
|
|
@ -23,8 +21,9 @@ class OnboardingSinglePage extends HookConsumerWidget {
|
|||
child: ConstrainedBox(
|
||||
constraints: BoxConstraints(
|
||||
maxWidth: 600,
|
||||
minWidth:
|
||||
constraints.maxWidth < 600 ? constraints.maxWidth : 0,
|
||||
minWidth: constraints.maxWidth < 600
|
||||
? constraints.maxWidth
|
||||
: 0,
|
||||
),
|
||||
child: const Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 20.0),
|
||||
|
|
@ -39,10 +38,7 @@ class OnboardingSinglePage extends HookConsumerWidget {
|
|||
}
|
||||
}
|
||||
|
||||
Widget fadeSlideTransitionBuilder(
|
||||
Widget child,
|
||||
Animation<double> animation,
|
||||
) {
|
||||
Widget fadeSlideTransitionBuilder(Widget child, Animation<double> animation) {
|
||||
return FadeTransition(
|
||||
opacity: animation,
|
||||
child: SlideTransition(
|
||||
|
|
@ -56,9 +52,7 @@ Widget fadeSlideTransitionBuilder(
|
|||
}
|
||||
|
||||
class OnboardingBody extends HookConsumerWidget {
|
||||
const OnboardingBody({
|
||||
super.key,
|
||||
});
|
||||
const OnboardingBody({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
|
|
@ -81,9 +75,7 @@ class OnboardingBody extends HookConsumerWidget {
|
|||
style: Theme.of(context).textTheme.headlineSmall,
|
||||
),
|
||||
),
|
||||
const SizedBox.square(
|
||||
dimension: 16.0,
|
||||
),
|
||||
const SizedBox.square(dimension: 16.0),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: AnimatedSwitcher(
|
||||
|
|
@ -112,21 +104,17 @@ class OnboardingBody extends HookConsumerWidget {
|
|||
},
|
||||
),
|
||||
),
|
||||
const SizedBox.square(
|
||||
dimension: 16.0,
|
||||
),
|
||||
const SizedBox.square(dimension: 16.0),
|
||||
AnimatedSwitcher(
|
||||
duration: 500.ms,
|
||||
transitionBuilder: fadeSlideTransitionBuilder,
|
||||
child: canUserLogin.value
|
||||
? UserLoginWidget(
|
||||
server: audiobookshelfUri,
|
||||
)
|
||||
? UserLoginWidget(server: audiobookshelfUri)
|
||||
// ).animate().fade(duration: 600.ms).slideY(begin: 0.3, end: 0)
|
||||
: const RedirectToABS().animate().fadeIn().slideY(
|
||||
curve: Curves.easeInOut,
|
||||
duration: 500.ms,
|
||||
),
|
||||
curve: Curves.easeInOut,
|
||||
duration: 500.ms,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
|
|
@ -134,9 +122,7 @@ class OnboardingBody extends HookConsumerWidget {
|
|||
}
|
||||
|
||||
class RedirectToABS extends StatelessWidget {
|
||||
const RedirectToABS({
|
||||
super.key,
|
||||
});
|
||||
const RedirectToABS({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
|
@ -152,18 +138,14 @@ class RedirectToABS extends StatelessWidget {
|
|||
isSemanticButton: false,
|
||||
style: ButtonStyle(
|
||||
elevation: WidgetStateProperty.all(0),
|
||||
padding: WidgetStateProperty.all(
|
||||
const EdgeInsets.all(0),
|
||||
),
|
||||
padding: WidgetStateProperty.all(const EdgeInsets.all(0)),
|
||||
),
|
||||
onPressed: () async {
|
||||
// open the github page
|
||||
// ignore: avoid_print
|
||||
print('Opening the github page');
|
||||
await handleLaunchUrl(
|
||||
Uri.parse(
|
||||
'https://www.audiobookshelf.org',
|
||||
),
|
||||
Uri.parse('https://www.audiobookshelf.org'),
|
||||
);
|
||||
},
|
||||
child: const Text('Click here'),
|
||||
|
|
|
|||
|
|
@ -22,11 +22,7 @@ import 'package:vaani/settings/api_settings_provider.dart'
|
|||
import 'package:vaani/settings/models/models.dart' as model;
|
||||
|
||||
class UserLoginWidget extends HookConsumerWidget {
|
||||
const UserLoginWidget({
|
||||
super.key,
|
||||
required this.server,
|
||||
this.onSuccess,
|
||||
});
|
||||
const UserLoginWidget({super.key, required this.server, this.onSuccess});
|
||||
|
||||
final Uri server;
|
||||
final Function(model.AuthenticatedUser)? onSuccess;
|
||||
|
|
@ -34,8 +30,9 @@ class UserLoginWidget extends HookConsumerWidget {
|
|||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final serverStatusError = useMemoized(() => ErrorResponseHandler(), []);
|
||||
final serverStatus =
|
||||
ref.watch(serverStatusProvider(server, serverStatusError.storeError));
|
||||
final serverStatus = ref.watch(
|
||||
serverStatusProvider(server, serverStatusError.storeError),
|
||||
);
|
||||
|
||||
return serverStatus.when(
|
||||
data: (value) {
|
||||
|
|
@ -55,9 +52,7 @@ class UserLoginWidget extends HookConsumerWidget {
|
|||
);
|
||||
},
|
||||
loading: () {
|
||||
return const Center(
|
||||
child: CircularProgressIndicator(),
|
||||
);
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
},
|
||||
error: (error, _) {
|
||||
return Center(
|
||||
|
|
@ -68,10 +63,7 @@ class UserLoginWidget extends HookConsumerWidget {
|
|||
ElevatedButton(
|
||||
onPressed: () {
|
||||
ref.invalidate(
|
||||
serverStatusProvider(
|
||||
server,
|
||||
serverStatusError.storeError,
|
||||
),
|
||||
serverStatusProvider(server, serverStatusError.storeError),
|
||||
);
|
||||
},
|
||||
child: const Text('Try again'),
|
||||
|
|
@ -84,11 +76,7 @@ class UserLoginWidget extends HookConsumerWidget {
|
|||
}
|
||||
}
|
||||
|
||||
enum AuthMethodChoice {
|
||||
local,
|
||||
openid,
|
||||
authToken,
|
||||
}
|
||||
enum AuthMethodChoice { local, openid, authToken }
|
||||
|
||||
class UserLoginMultipleAuth extends HookConsumerWidget {
|
||||
const UserLoginMultipleAuth({
|
||||
|
|
@ -117,21 +105,17 @@ class UserLoginMultipleAuth extends HookConsumerWidget {
|
|||
);
|
||||
|
||||
model.AudiobookShelfServer addServer() {
|
||||
var newServer = model.AudiobookShelfServer(
|
||||
serverUrl: server,
|
||||
);
|
||||
var newServer = model.AudiobookShelfServer(serverUrl: server);
|
||||
try {
|
||||
// add the server to the list of servers
|
||||
ref.read(audiobookShelfServerProvider.notifier).addServer(
|
||||
newServer,
|
||||
);
|
||||
ref.read(audiobookShelfServerProvider.notifier).addServer(newServer);
|
||||
} on ServerAlreadyExistsException catch (e) {
|
||||
newServer = e.server;
|
||||
} finally {
|
||||
ref.read(apiSettingsProvider.notifier).updateState(
|
||||
ref.read(apiSettingsProvider).copyWith(
|
||||
activeServer: newServer,
|
||||
),
|
||||
ref
|
||||
.read(apiSettingsProvider.notifier)
|
||||
.updateState(
|
||||
ref.read(apiSettingsProvider).copyWith(activeServer: newServer),
|
||||
);
|
||||
}
|
||||
return newServer;
|
||||
|
|
@ -150,42 +134,49 @@ class UserLoginMultipleAuth extends HookConsumerWidget {
|
|||
runAlignment: WrapAlignment.center,
|
||||
runSpacing: 10,
|
||||
alignment: WrapAlignment.center,
|
||||
children: [
|
||||
// a small label to show the user what to do
|
||||
if (localAvailable)
|
||||
ChoiceChip(
|
||||
label: const Text('Local'),
|
||||
selected: methodChoice.value == AuthMethodChoice.local,
|
||||
onSelected: (selected) {
|
||||
if (selected) {
|
||||
methodChoice.value = AuthMethodChoice.local;
|
||||
}
|
||||
},
|
||||
),
|
||||
if (openIDAvailable)
|
||||
ChoiceChip(
|
||||
label: const Text('OpenID'),
|
||||
selected: methodChoice.value == AuthMethodChoice.openid,
|
||||
onSelected: (selected) {
|
||||
if (selected) {
|
||||
methodChoice.value = AuthMethodChoice.openid;
|
||||
}
|
||||
},
|
||||
),
|
||||
ChoiceChip(
|
||||
label: const Text('Token'),
|
||||
selected:
|
||||
methodChoice.value == AuthMethodChoice.authToken,
|
||||
onSelected: (selected) {
|
||||
if (selected) {
|
||||
methodChoice.value = AuthMethodChoice.authToken;
|
||||
}
|
||||
},
|
||||
),
|
||||
].animate(interval: 100.ms).fadeIn(
|
||||
duration: 150.ms,
|
||||
curve: Curves.easeIn,
|
||||
),
|
||||
children:
|
||||
[
|
||||
// a small label to show the user what to do
|
||||
if (localAvailable)
|
||||
ChoiceChip(
|
||||
label: const Text('Local'),
|
||||
selected:
|
||||
methodChoice.value ==
|
||||
AuthMethodChoice.local,
|
||||
onSelected: (selected) {
|
||||
if (selected) {
|
||||
methodChoice.value = AuthMethodChoice.local;
|
||||
}
|
||||
},
|
||||
),
|
||||
if (openIDAvailable)
|
||||
ChoiceChip(
|
||||
label: const Text('OpenID'),
|
||||
selected:
|
||||
methodChoice.value ==
|
||||
AuthMethodChoice.openid,
|
||||
onSelected: (selected) {
|
||||
if (selected) {
|
||||
methodChoice.value =
|
||||
AuthMethodChoice.openid;
|
||||
}
|
||||
},
|
||||
),
|
||||
ChoiceChip(
|
||||
label: const Text('Token'),
|
||||
selected:
|
||||
methodChoice.value ==
|
||||
AuthMethodChoice.authToken,
|
||||
onSelected: (selected) {
|
||||
if (selected) {
|
||||
methodChoice.value =
|
||||
AuthMethodChoice.authToken;
|
||||
}
|
||||
},
|
||||
),
|
||||
]
|
||||
.animate(interval: 100.ms)
|
||||
.fadeIn(duration: 150.ms, curve: Curves.easeIn),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
|
|
@ -195,21 +186,21 @@ class UserLoginMultipleAuth extends HookConsumerWidget {
|
|||
transitionBuilder: fadeSlideTransitionBuilder,
|
||||
child: switch (methodChoice.value) {
|
||||
AuthMethodChoice.authToken => UserLoginWithToken(
|
||||
server: server,
|
||||
addServer: addServer,
|
||||
onSuccess: onSuccess,
|
||||
),
|
||||
server: server,
|
||||
addServer: addServer,
|
||||
onSuccess: onSuccess,
|
||||
),
|
||||
AuthMethodChoice.local => UserLoginWithPassword(
|
||||
server: server,
|
||||
addServer: addServer,
|
||||
onSuccess: onSuccess,
|
||||
),
|
||||
server: server,
|
||||
addServer: addServer,
|
||||
onSuccess: onSuccess,
|
||||
),
|
||||
AuthMethodChoice.openid => UserLoginWithOpenID(
|
||||
server: server,
|
||||
addServer: addServer,
|
||||
openIDButtonText: openIDButtonText,
|
||||
onSuccess: onSuccess,
|
||||
),
|
||||
server: server,
|
||||
addServer: addServer,
|
||||
openIDButtonText: openIDButtonText,
|
||||
onSuccess: onSuccess,
|
||||
),
|
||||
},
|
||||
),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -54,9 +54,9 @@ class UserLoginWithOpenID extends HookConsumerWidget {
|
|||
|
||||
if (openIDLoginEndpoint == null) {
|
||||
if (responseErrorHandler.response.statusCode == 400 &&
|
||||
responseErrorHandler.response.body
|
||||
.toLowerCase()
|
||||
.contains(RegExp(r'invalid.*redirect.*uri'))) {
|
||||
responseErrorHandler.response.body.toLowerCase().contains(
|
||||
RegExp(r'invalid.*redirect.*uri'),
|
||||
)) {
|
||||
// show error
|
||||
handleServerError(
|
||||
context,
|
||||
|
|
@ -97,16 +97,16 @@ class UserLoginWithOpenID extends HookConsumerWidget {
|
|||
);
|
||||
|
||||
// add the flow to the provider
|
||||
ref.read(oauthFlowsProvider.notifier).addFlow(
|
||||
ref
|
||||
.read(oauthFlowsProvider.notifier)
|
||||
.addFlow(
|
||||
oauthState,
|
||||
verifier: verifier,
|
||||
serverUri: server,
|
||||
cookie: Cookie.fromSetCookieValue(authCookie!),
|
||||
);
|
||||
|
||||
await handleLaunchUrl(
|
||||
openIDLoginEndpoint,
|
||||
);
|
||||
await handleLaunchUrl(openIDLoginEndpoint);
|
||||
}
|
||||
|
||||
return Column(
|
||||
|
|
|
|||
|
|
@ -39,17 +39,14 @@ class UserLoginWithPassword extends HookConsumerWidget {
|
|||
final api = ref.watch(audiobookshelfApiProvider(server));
|
||||
|
||||
// forward animation when the password visibility changes
|
||||
useEffect(
|
||||
() {
|
||||
if (isPasswordVisible.value) {
|
||||
isPasswordVisibleAnimationController.forward();
|
||||
} else {
|
||||
isPasswordVisibleAnimationController.reverse();
|
||||
}
|
||||
return null;
|
||||
},
|
||||
[isPasswordVisible.value],
|
||||
);
|
||||
useEffect(() {
|
||||
if (isPasswordVisible.value) {
|
||||
isPasswordVisibleAnimationController.forward();
|
||||
} else {
|
||||
isPasswordVisibleAnimationController.reverse();
|
||||
}
|
||||
return null;
|
||||
}, [isPasswordVisible.value]);
|
||||
|
||||
/// Login to the server and save the user
|
||||
Future<void> loginAndSave() async {
|
||||
|
|
@ -109,10 +106,9 @@ class UserLoginWithPassword extends HookConsumerWidget {
|
|||
decoration: InputDecoration(
|
||||
labelText: 'Username',
|
||||
labelStyle: TextStyle(
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.onSurface
|
||||
.withValues(alpha: 0.8),
|
||||
color: Theme.of(
|
||||
context,
|
||||
).colorScheme.onSurface.withValues(alpha: 0.8),
|
||||
),
|
||||
border: const OutlineInputBorder(),
|
||||
),
|
||||
|
|
@ -129,18 +125,16 @@ class UserLoginWithPassword extends HookConsumerWidget {
|
|||
decoration: InputDecoration(
|
||||
labelText: 'Password',
|
||||
labelStyle: TextStyle(
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.onSurface
|
||||
.withValues(alpha: 0.8),
|
||||
color: Theme.of(
|
||||
context,
|
||||
).colorScheme.onSurface.withValues(alpha: 0.8),
|
||||
),
|
||||
border: const OutlineInputBorder(),
|
||||
suffixIcon: ColorFiltered(
|
||||
colorFilter: ColorFilter.mode(
|
||||
Theme.of(context)
|
||||
.colorScheme
|
||||
.primary
|
||||
.withValues(alpha: 0.8),
|
||||
Theme.of(
|
||||
context,
|
||||
).colorScheme.primary.withValues(alpha: 0.8),
|
||||
BlendMode.srcIn,
|
||||
),
|
||||
child: InkWell(
|
||||
|
|
@ -157,9 +151,7 @@ class UserLoginWithPassword extends HookConsumerWidget {
|
|||
),
|
||||
),
|
||||
),
|
||||
suffixIconConstraints: const BoxConstraints(
|
||||
maxHeight: 45,
|
||||
),
|
||||
suffixIconConstraints: const BoxConstraints(maxHeight: 45),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 30),
|
||||
|
|
@ -197,10 +189,12 @@ Future<void> handleServerError(
|
|||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
title: const Text('Error'),
|
||||
content: SelectableText('$title\n'
|
||||
'Got response: ${responseErrorHandler.response.body} (${responseErrorHandler.response.statusCode})\n'
|
||||
'Stacktrace: $e\n\n'
|
||||
'$body\n\n'),
|
||||
content: SelectableText(
|
||||
'$title\n'
|
||||
'Got response: ${responseErrorHandler.response.body} (${responseErrorHandler.response.statusCode})\n'
|
||||
'Stacktrace: $e\n\n'
|
||||
'$body\n\n',
|
||||
),
|
||||
actions: [
|
||||
if (outLink != null)
|
||||
TextButton(
|
||||
|
|
@ -214,8 +208,8 @@ Future<void> handleServerError(
|
|||
// open an issue on the github page
|
||||
handleLaunchUrl(
|
||||
AppMetadata.githubRepo
|
||||
// append the issue url
|
||||
.replace(
|
||||
// append the issue url
|
||||
.replace(
|
||||
path: '${AppMetadata.githubRepo.path}/issues/new',
|
||||
),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -89,10 +89,9 @@ class UserLoginWithToken extends HookConsumerWidget {
|
|||
decoration: InputDecoration(
|
||||
labelText: 'API Token',
|
||||
labelStyle: TextStyle(
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.onSurface
|
||||
.withValues(alpha: 0.8),
|
||||
color: Theme.of(
|
||||
context,
|
||||
).colorScheme.onSurface.withValues(alpha: 0.8),
|
||||
),
|
||||
border: const OutlineInputBorder(),
|
||||
),
|
||||
|
|
@ -107,10 +106,7 @@ class UserLoginWithToken extends HookConsumerWidget {
|
|||
},
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
ElevatedButton(
|
||||
onPressed: loginAndSave,
|
||||
child: const Text('Login'),
|
||||
),
|
||||
ElevatedButton(onPressed: loginAndSave, child: const Text('Login')),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ part 'book_settings.g.dart';
|
|||
|
||||
/// per book settings
|
||||
@freezed
|
||||
class BookSettings with _$BookSettings {
|
||||
sealed class BookSettings with _$BookSettings {
|
||||
const factory BookSettings({
|
||||
required String bookId,
|
||||
@Default(NullablePlayerSettings()) NullablePlayerSettings playerSettings,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
// coverage:ignore-file
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// coverage:ignore-file
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
|
||||
|
||||
|
|
@ -9,195 +9,284 @@ part of 'book_settings.dart';
|
|||
// FreezedGenerator
|
||||
// **************************************************************************
|
||||
|
||||
// dart format off
|
||||
T _$identity<T>(T value) => value;
|
||||
|
||||
final _privateConstructorUsedError = UnsupportedError(
|
||||
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models');
|
||||
|
||||
BookSettings _$BookSettingsFromJson(Map<String, dynamic> json) {
|
||||
return _BookSettings.fromJson(json);
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
mixin _$BookSettings {
|
||||
String get bookId => throw _privateConstructorUsedError;
|
||||
NullablePlayerSettings get playerSettings =>
|
||||
throw _privateConstructorUsedError;
|
||||
|
||||
String get bookId; NullablePlayerSettings get playerSettings;
|
||||
/// Create a copy of BookSettings
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
$BookSettingsCopyWith<BookSettings> get copyWith => _$BookSettingsCopyWithImpl<BookSettings>(this as BookSettings, _$identity);
|
||||
|
||||
/// Serializes this BookSettings to a JSON map.
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
Map<String, dynamic> toJson();
|
||||
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is BookSettings&&(identical(other.bookId, bookId) || other.bookId == bookId)&&(identical(other.playerSettings, playerSettings) || other.playerSettings == playerSettings));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,bookId,playerSettings);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'BookSettings(bookId: $bookId, playerSettings: $playerSettings)';
|
||||
}
|
||||
|
||||
|
||||
/// Create a copy of BookSettings
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
$BookSettingsCopyWith<BookSettings> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $BookSettingsCopyWith<$Res> {
|
||||
factory $BookSettingsCopyWith(
|
||||
BookSettings value, $Res Function(BookSettings) then) =
|
||||
_$BookSettingsCopyWithImpl<$Res, BookSettings>;
|
||||
@useResult
|
||||
$Res call({String bookId, NullablePlayerSettings playerSettings});
|
||||
abstract mixin class $BookSettingsCopyWith<$Res> {
|
||||
factory $BookSettingsCopyWith(BookSettings value, $Res Function(BookSettings) _then) = _$BookSettingsCopyWithImpl;
|
||||
@useResult
|
||||
$Res call({
|
||||
String bookId, NullablePlayerSettings playerSettings
|
||||
});
|
||||
|
||||
|
||||
$NullablePlayerSettingsCopyWith<$Res> get playerSettings;
|
||||
|
||||
$NullablePlayerSettingsCopyWith<$Res> get playerSettings;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$BookSettingsCopyWithImpl<$Res, $Val extends BookSettings>
|
||||
class _$BookSettingsCopyWithImpl<$Res>
|
||||
implements $BookSettingsCopyWith<$Res> {
|
||||
_$BookSettingsCopyWithImpl(this._value, this._then);
|
||||
_$BookSettingsCopyWithImpl(this._self, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
final BookSettings _self;
|
||||
final $Res Function(BookSettings) _then;
|
||||
|
||||
/// Create a copy of BookSettings
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? bookId = null,
|
||||
Object? playerSettings = null,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
bookId: null == bookId
|
||||
? _value.bookId
|
||||
: bookId // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
playerSettings: null == playerSettings
|
||||
? _value.playerSettings
|
||||
: playerSettings // ignore: cast_nullable_to_non_nullable
|
||||
as NullablePlayerSettings,
|
||||
) as $Val);
|
||||
}
|
||||
|
||||
/// Create a copy of BookSettings
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$NullablePlayerSettingsCopyWith<$Res> get playerSettings {
|
||||
return $NullablePlayerSettingsCopyWith<$Res>(_value.playerSettings,
|
||||
(value) {
|
||||
return _then(_value.copyWith(playerSettings: value) as $Val);
|
||||
});
|
||||
}
|
||||
/// Create a copy of BookSettings
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? bookId = null,Object? playerSettings = null,}) {
|
||||
return _then(_self.copyWith(
|
||||
bookId: null == bookId ? _self.bookId : bookId // ignore: cast_nullable_to_non_nullable
|
||||
as String,playerSettings: null == playerSettings ? _self.playerSettings : playerSettings // ignore: cast_nullable_to_non_nullable
|
||||
as NullablePlayerSettings,
|
||||
));
|
||||
}
|
||||
/// Create a copy of BookSettings
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$NullablePlayerSettingsCopyWith<$Res> get playerSettings {
|
||||
|
||||
return $NullablePlayerSettingsCopyWith<$Res>(_self.playerSettings, (value) {
|
||||
return _then(_self.copyWith(playerSettings: value));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$BookSettingsImplCopyWith<$Res>
|
||||
implements $BookSettingsCopyWith<$Res> {
|
||||
factory _$$BookSettingsImplCopyWith(
|
||||
_$BookSettingsImpl value, $Res Function(_$BookSettingsImpl) then) =
|
||||
__$$BookSettingsImplCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call({String bookId, NullablePlayerSettings playerSettings});
|
||||
|
||||
@override
|
||||
$NullablePlayerSettingsCopyWith<$Res> get playerSettings;
|
||||
/// Adds pattern-matching-related methods to [BookSettings].
|
||||
extension BookSettingsPatterns on BookSettings {
|
||||
/// A variant of `map` that fallback to returning `orElse`.
|
||||
///
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case final Subclass value:
|
||||
/// return ...;
|
||||
/// case _:
|
||||
/// return orElse();
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _BookSettings value)? $default,{required TResult orElse(),}){
|
||||
final _that = this;
|
||||
switch (_that) {
|
||||
case _BookSettings() when $default != null:
|
||||
return $default(_that);case _:
|
||||
return orElse();
|
||||
|
||||
}
|
||||
}
|
||||
/// A `switch`-like method, using callbacks.
|
||||
///
|
||||
/// Callbacks receives the raw object, upcasted.
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case final Subclass value:
|
||||
/// return ...;
|
||||
/// case final Subclass2 value:
|
||||
/// return ...;
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _BookSettings value) $default,){
|
||||
final _that = this;
|
||||
switch (_that) {
|
||||
case _BookSettings():
|
||||
return $default(_that);}
|
||||
}
|
||||
/// A variant of `map` that fallback to returning `null`.
|
||||
///
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case final Subclass value:
|
||||
/// return ...;
|
||||
/// case _:
|
||||
/// return null;
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _BookSettings value)? $default,){
|
||||
final _that = this;
|
||||
switch (_that) {
|
||||
case _BookSettings() when $default != null:
|
||||
return $default(_that);case _:
|
||||
return null;
|
||||
|
||||
}
|
||||
}
|
||||
/// A variant of `when` that fallback to an `orElse` callback.
|
||||
///
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case Subclass(:final field):
|
||||
/// return ...;
|
||||
/// case _:
|
||||
/// return orElse();
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String bookId, NullablePlayerSettings playerSettings)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
switch (_that) {
|
||||
case _BookSettings() when $default != null:
|
||||
return $default(_that.bookId,_that.playerSettings);case _:
|
||||
return orElse();
|
||||
|
||||
}
|
||||
}
|
||||
/// A `switch`-like method, using callbacks.
|
||||
///
|
||||
/// As opposed to `map`, this offers destructuring.
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case Subclass(:final field):
|
||||
/// return ...;
|
||||
/// case Subclass2(:final field2):
|
||||
/// return ...;
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String bookId, NullablePlayerSettings playerSettings) $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _BookSettings():
|
||||
return $default(_that.bookId,_that.playerSettings);}
|
||||
}
|
||||
/// A variant of `when` that fallback to returning `null`
|
||||
///
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case Subclass(:final field):
|
||||
/// return ...;
|
||||
/// case _:
|
||||
/// return null;
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String bookId, NullablePlayerSettings playerSettings)? $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _BookSettings() when $default != null:
|
||||
return $default(_that.bookId,_that.playerSettings);case _:
|
||||
return null;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$BookSettingsImplCopyWithImpl<$Res>
|
||||
extends _$BookSettingsCopyWithImpl<$Res, _$BookSettingsImpl>
|
||||
implements _$$BookSettingsImplCopyWith<$Res> {
|
||||
__$$BookSettingsImplCopyWithImpl(
|
||||
_$BookSettingsImpl _value, $Res Function(_$BookSettingsImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of BookSettings
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? bookId = null,
|
||||
Object? playerSettings = null,
|
||||
}) {
|
||||
return _then(_$BookSettingsImpl(
|
||||
bookId: null == bookId
|
||||
? _value.bookId
|
||||
: bookId // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
playerSettings: null == playerSettings
|
||||
? _value.playerSettings
|
||||
: playerSettings // ignore: cast_nullable_to_non_nullable
|
||||
as NullablePlayerSettings,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@JsonSerializable()
|
||||
class _$BookSettingsImpl implements _BookSettings {
|
||||
const _$BookSettingsImpl(
|
||||
{required this.bookId,
|
||||
this.playerSettings = const NullablePlayerSettings()});
|
||||
|
||||
factory _$BookSettingsImpl.fromJson(Map<String, dynamic> json) =>
|
||||
_$$BookSettingsImplFromJson(json);
|
||||
class _BookSettings implements BookSettings {
|
||||
const _BookSettings({required this.bookId, this.playerSettings = const NullablePlayerSettings()});
|
||||
factory _BookSettings.fromJson(Map<String, dynamic> json) => _$BookSettingsFromJson(json);
|
||||
|
||||
@override
|
||||
final String bookId;
|
||||
@override
|
||||
@JsonKey()
|
||||
final NullablePlayerSettings playerSettings;
|
||||
@override final String bookId;
|
||||
@override@JsonKey() final NullablePlayerSettings playerSettings;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'BookSettings(bookId: $bookId, playerSettings: $playerSettings)';
|
||||
}
|
||||
/// Create a copy of BookSettings
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
_$BookSettingsCopyWith<_BookSettings> get copyWith => __$BookSettingsCopyWithImpl<_BookSettings>(this, _$identity);
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$BookSettingsImpl &&
|
||||
(identical(other.bookId, bookId) || other.bookId == bookId) &&
|
||||
(identical(other.playerSettings, playerSettings) ||
|
||||
other.playerSettings == playerSettings));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, bookId, playerSettings);
|
||||
|
||||
/// Create a copy of BookSettings
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$BookSettingsImplCopyWith<_$BookSettingsImpl> get copyWith =>
|
||||
__$$BookSettingsImplCopyWithImpl<_$BookSettingsImpl>(this, _$identity);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return _$$BookSettingsImplToJson(
|
||||
this,
|
||||
);
|
||||
}
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return _$BookSettingsToJson(this, );
|
||||
}
|
||||
|
||||
abstract class _BookSettings implements BookSettings {
|
||||
const factory _BookSettings(
|
||||
{required final String bookId,
|
||||
final NullablePlayerSettings playerSettings}) = _$BookSettingsImpl;
|
||||
|
||||
factory _BookSettings.fromJson(Map<String, dynamic> json) =
|
||||
_$BookSettingsImpl.fromJson;
|
||||
|
||||
@override
|
||||
String get bookId;
|
||||
@override
|
||||
NullablePlayerSettings get playerSettings;
|
||||
|
||||
/// Create a copy of BookSettings
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$BookSettingsImplCopyWith<_$BookSettingsImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _BookSettings&&(identical(other.bookId, bookId) || other.bookId == bookId)&&(identical(other.playerSettings, playerSettings) || other.playerSettings == playerSettings));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,bookId,playerSettings);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'BookSettings(bookId: $bookId, playerSettings: $playerSettings)';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class _$BookSettingsCopyWith<$Res> implements $BookSettingsCopyWith<$Res> {
|
||||
factory _$BookSettingsCopyWith(_BookSettings value, $Res Function(_BookSettings) _then) = __$BookSettingsCopyWithImpl;
|
||||
@override @useResult
|
||||
$Res call({
|
||||
String bookId, NullablePlayerSettings playerSettings
|
||||
});
|
||||
|
||||
|
||||
@override $NullablePlayerSettingsCopyWith<$Res> get playerSettings;
|
||||
|
||||
}
|
||||
/// @nodoc
|
||||
class __$BookSettingsCopyWithImpl<$Res>
|
||||
implements _$BookSettingsCopyWith<$Res> {
|
||||
__$BookSettingsCopyWithImpl(this._self, this._then);
|
||||
|
||||
final _BookSettings _self;
|
||||
final $Res Function(_BookSettings) _then;
|
||||
|
||||
/// Create a copy of BookSettings
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? bookId = null,Object? playerSettings = null,}) {
|
||||
return _then(_BookSettings(
|
||||
bookId: null == bookId ? _self.bookId : bookId // ignore: cast_nullable_to_non_nullable
|
||||
as String,playerSettings: null == playerSettings ? _self.playerSettings : playerSettings // ignore: cast_nullable_to_non_nullable
|
||||
as NullablePlayerSettings,
|
||||
));
|
||||
}
|
||||
|
||||
/// Create a copy of BookSettings
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$NullablePlayerSettingsCopyWith<$Res> get playerSettings {
|
||||
|
||||
return $NullablePlayerSettingsCopyWith<$Res>(_self.playerSettings, (value) {
|
||||
return _then(_self.copyWith(playerSettings: value));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// dart format on
|
||||
|
|
|
|||
|
|
@ -6,16 +6,17 @@ part of 'book_settings.dart';
|
|||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
_$BookSettingsImpl _$$BookSettingsImplFromJson(Map<String, dynamic> json) =>
|
||||
_$BookSettingsImpl(
|
||||
_BookSettings _$BookSettingsFromJson(Map<String, dynamic> json) =>
|
||||
_BookSettings(
|
||||
bookId: json['bookId'] as String,
|
||||
playerSettings: json['playerSettings'] == null
|
||||
? const NullablePlayerSettings()
|
||||
: NullablePlayerSettings.fromJson(
|
||||
json['playerSettings'] as Map<String, dynamic>),
|
||||
json['playerSettings'] as Map<String, dynamic>,
|
||||
),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$BookSettingsImplToJson(_$BookSettingsImpl instance) =>
|
||||
Map<String, dynamic> _$BookSettingsToJson(_BookSettings instance) =>
|
||||
<String, dynamic>{
|
||||
'bookId': instance.bookId,
|
||||
'playerSettings': instance.playerSettings,
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ part 'nullable_player_settings.freezed.dart';
|
|||
part 'nullable_player_settings.g.dart';
|
||||
|
||||
@freezed
|
||||
class NullablePlayerSettings with _$NullablePlayerSettings {
|
||||
sealed class NullablePlayerSettings with _$NullablePlayerSettings {
|
||||
const factory NullablePlayerSettings({
|
||||
MinimizedPlayerSettings? miniPlayerSettings,
|
||||
ExpandedPlayerSettings? expandedPlayerSettings,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
// coverage:ignore-file
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// coverage:ignore-file
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
|
||||
|
||||
|
|
@ -9,369 +9,361 @@ part of 'nullable_player_settings.dart';
|
|||
// FreezedGenerator
|
||||
// **************************************************************************
|
||||
|
||||
// dart format off
|
||||
T _$identity<T>(T value) => value;
|
||||
|
||||
final _privateConstructorUsedError = UnsupportedError(
|
||||
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models');
|
||||
|
||||
NullablePlayerSettings _$NullablePlayerSettingsFromJson(
|
||||
Map<String, dynamic> json) {
|
||||
return _NullablePlayerSettings.fromJson(json);
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
mixin _$NullablePlayerSettings {
|
||||
MinimizedPlayerSettings? get miniPlayerSettings =>
|
||||
throw _privateConstructorUsedError;
|
||||
ExpandedPlayerSettings? get expandedPlayerSettings =>
|
||||
throw _privateConstructorUsedError;
|
||||
double? get preferredDefaultVolume => throw _privateConstructorUsedError;
|
||||
double? get preferredDefaultSpeed => throw _privateConstructorUsedError;
|
||||
List<double>? get speedOptions => throw _privateConstructorUsedError;
|
||||
SleepTimerSettings? get sleepTimerSettings =>
|
||||
throw _privateConstructorUsedError;
|
||||
Duration? get playbackReportInterval => throw _privateConstructorUsedError;
|
||||
|
||||
MinimizedPlayerSettings? get miniPlayerSettings; ExpandedPlayerSettings? get expandedPlayerSettings; double? get preferredDefaultVolume; double? get preferredDefaultSpeed; List<double>? get speedOptions; SleepTimerSettings? get sleepTimerSettings; Duration? get playbackReportInterval;
|
||||
/// Create a copy of NullablePlayerSettings
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
$NullablePlayerSettingsCopyWith<NullablePlayerSettings> get copyWith => _$NullablePlayerSettingsCopyWithImpl<NullablePlayerSettings>(this as NullablePlayerSettings, _$identity);
|
||||
|
||||
/// Serializes this NullablePlayerSettings to a JSON map.
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
Map<String, dynamic> toJson();
|
||||
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is NullablePlayerSettings&&(identical(other.miniPlayerSettings, miniPlayerSettings) || other.miniPlayerSettings == miniPlayerSettings)&&(identical(other.expandedPlayerSettings, expandedPlayerSettings) || other.expandedPlayerSettings == expandedPlayerSettings)&&(identical(other.preferredDefaultVolume, preferredDefaultVolume) || other.preferredDefaultVolume == preferredDefaultVolume)&&(identical(other.preferredDefaultSpeed, preferredDefaultSpeed) || other.preferredDefaultSpeed == preferredDefaultSpeed)&&const DeepCollectionEquality().equals(other.speedOptions, speedOptions)&&(identical(other.sleepTimerSettings, sleepTimerSettings) || other.sleepTimerSettings == sleepTimerSettings)&&(identical(other.playbackReportInterval, playbackReportInterval) || other.playbackReportInterval == playbackReportInterval));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,miniPlayerSettings,expandedPlayerSettings,preferredDefaultVolume,preferredDefaultSpeed,const DeepCollectionEquality().hash(speedOptions),sleepTimerSettings,playbackReportInterval);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'NullablePlayerSettings(miniPlayerSettings: $miniPlayerSettings, expandedPlayerSettings: $expandedPlayerSettings, preferredDefaultVolume: $preferredDefaultVolume, preferredDefaultSpeed: $preferredDefaultSpeed, speedOptions: $speedOptions, sleepTimerSettings: $sleepTimerSettings, playbackReportInterval: $playbackReportInterval)';
|
||||
}
|
||||
|
||||
|
||||
/// Create a copy of NullablePlayerSettings
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
$NullablePlayerSettingsCopyWith<NullablePlayerSettings> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $NullablePlayerSettingsCopyWith<$Res> {
|
||||
factory $NullablePlayerSettingsCopyWith(NullablePlayerSettings value,
|
||||
$Res Function(NullablePlayerSettings) then) =
|
||||
_$NullablePlayerSettingsCopyWithImpl<$Res, NullablePlayerSettings>;
|
||||
@useResult
|
||||
$Res call(
|
||||
{MinimizedPlayerSettings? miniPlayerSettings,
|
||||
ExpandedPlayerSettings? expandedPlayerSettings,
|
||||
double? preferredDefaultVolume,
|
||||
double? preferredDefaultSpeed,
|
||||
List<double>? speedOptions,
|
||||
SleepTimerSettings? sleepTimerSettings,
|
||||
Duration? playbackReportInterval});
|
||||
abstract mixin class $NullablePlayerSettingsCopyWith<$Res> {
|
||||
factory $NullablePlayerSettingsCopyWith(NullablePlayerSettings value, $Res Function(NullablePlayerSettings) _then) = _$NullablePlayerSettingsCopyWithImpl;
|
||||
@useResult
|
||||
$Res call({
|
||||
MinimizedPlayerSettings? miniPlayerSettings, ExpandedPlayerSettings? expandedPlayerSettings, double? preferredDefaultVolume, double? preferredDefaultSpeed, List<double>? speedOptions, SleepTimerSettings? sleepTimerSettings, Duration? playbackReportInterval
|
||||
});
|
||||
|
||||
|
||||
$MinimizedPlayerSettingsCopyWith<$Res>? get miniPlayerSettings;$ExpandedPlayerSettingsCopyWith<$Res>? get expandedPlayerSettings;$SleepTimerSettingsCopyWith<$Res>? get sleepTimerSettings;
|
||||
|
||||
$MinimizedPlayerSettingsCopyWith<$Res>? get miniPlayerSettings;
|
||||
$ExpandedPlayerSettingsCopyWith<$Res>? get expandedPlayerSettings;
|
||||
$SleepTimerSettingsCopyWith<$Res>? get sleepTimerSettings;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$NullablePlayerSettingsCopyWithImpl<$Res,
|
||||
$Val extends NullablePlayerSettings>
|
||||
class _$NullablePlayerSettingsCopyWithImpl<$Res>
|
||||
implements $NullablePlayerSettingsCopyWith<$Res> {
|
||||
_$NullablePlayerSettingsCopyWithImpl(this._value, this._then);
|
||||
_$NullablePlayerSettingsCopyWithImpl(this._self, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
final NullablePlayerSettings _self;
|
||||
final $Res Function(NullablePlayerSettings) _then;
|
||||
|
||||
/// Create a copy of NullablePlayerSettings
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? miniPlayerSettings = freezed,
|
||||
Object? expandedPlayerSettings = freezed,
|
||||
Object? preferredDefaultVolume = freezed,
|
||||
Object? preferredDefaultSpeed = freezed,
|
||||
Object? speedOptions = freezed,
|
||||
Object? sleepTimerSettings = freezed,
|
||||
Object? playbackReportInterval = freezed,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
miniPlayerSettings: freezed == miniPlayerSettings
|
||||
? _value.miniPlayerSettings
|
||||
: miniPlayerSettings // ignore: cast_nullable_to_non_nullable
|
||||
as MinimizedPlayerSettings?,
|
||||
expandedPlayerSettings: freezed == expandedPlayerSettings
|
||||
? _value.expandedPlayerSettings
|
||||
: expandedPlayerSettings // ignore: cast_nullable_to_non_nullable
|
||||
as ExpandedPlayerSettings?,
|
||||
preferredDefaultVolume: freezed == preferredDefaultVolume
|
||||
? _value.preferredDefaultVolume
|
||||
: preferredDefaultVolume // ignore: cast_nullable_to_non_nullable
|
||||
as double?,
|
||||
preferredDefaultSpeed: freezed == preferredDefaultSpeed
|
||||
? _value.preferredDefaultSpeed
|
||||
: preferredDefaultSpeed // ignore: cast_nullable_to_non_nullable
|
||||
as double?,
|
||||
speedOptions: freezed == speedOptions
|
||||
? _value.speedOptions
|
||||
: speedOptions // ignore: cast_nullable_to_non_nullable
|
||||
as List<double>?,
|
||||
sleepTimerSettings: freezed == sleepTimerSettings
|
||||
? _value.sleepTimerSettings
|
||||
: sleepTimerSettings // ignore: cast_nullable_to_non_nullable
|
||||
as SleepTimerSettings?,
|
||||
playbackReportInterval: freezed == playbackReportInterval
|
||||
? _value.playbackReportInterval
|
||||
: playbackReportInterval // ignore: cast_nullable_to_non_nullable
|
||||
as Duration?,
|
||||
) as $Val);
|
||||
/// Create a copy of NullablePlayerSettings
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? miniPlayerSettings = freezed,Object? expandedPlayerSettings = freezed,Object? preferredDefaultVolume = freezed,Object? preferredDefaultSpeed = freezed,Object? speedOptions = freezed,Object? sleepTimerSettings = freezed,Object? playbackReportInterval = freezed,}) {
|
||||
return _then(_self.copyWith(
|
||||
miniPlayerSettings: freezed == miniPlayerSettings ? _self.miniPlayerSettings : miniPlayerSettings // ignore: cast_nullable_to_non_nullable
|
||||
as MinimizedPlayerSettings?,expandedPlayerSettings: freezed == expandedPlayerSettings ? _self.expandedPlayerSettings : expandedPlayerSettings // ignore: cast_nullable_to_non_nullable
|
||||
as ExpandedPlayerSettings?,preferredDefaultVolume: freezed == preferredDefaultVolume ? _self.preferredDefaultVolume : preferredDefaultVolume // ignore: cast_nullable_to_non_nullable
|
||||
as double?,preferredDefaultSpeed: freezed == preferredDefaultSpeed ? _self.preferredDefaultSpeed : preferredDefaultSpeed // ignore: cast_nullable_to_non_nullable
|
||||
as double?,speedOptions: freezed == speedOptions ? _self.speedOptions : speedOptions // ignore: cast_nullable_to_non_nullable
|
||||
as List<double>?,sleepTimerSettings: freezed == sleepTimerSettings ? _self.sleepTimerSettings : sleepTimerSettings // ignore: cast_nullable_to_non_nullable
|
||||
as SleepTimerSettings?,playbackReportInterval: freezed == playbackReportInterval ? _self.playbackReportInterval : playbackReportInterval // ignore: cast_nullable_to_non_nullable
|
||||
as Duration?,
|
||||
));
|
||||
}
|
||||
/// Create a copy of NullablePlayerSettings
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$MinimizedPlayerSettingsCopyWith<$Res>? get miniPlayerSettings {
|
||||
if (_self.miniPlayerSettings == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/// Create a copy of NullablePlayerSettings
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$MinimizedPlayerSettingsCopyWith<$Res>? get miniPlayerSettings {
|
||||
if (_value.miniPlayerSettings == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $MinimizedPlayerSettingsCopyWith<$Res>(_value.miniPlayerSettings!,
|
||||
(value) {
|
||||
return _then(_value.copyWith(miniPlayerSettings: value) as $Val);
|
||||
});
|
||||
return $MinimizedPlayerSettingsCopyWith<$Res>(_self.miniPlayerSettings!, (value) {
|
||||
return _then(_self.copyWith(miniPlayerSettings: value));
|
||||
});
|
||||
}/// Create a copy of NullablePlayerSettings
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$ExpandedPlayerSettingsCopyWith<$Res>? get expandedPlayerSettings {
|
||||
if (_self.expandedPlayerSettings == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/// Create a copy of NullablePlayerSettings
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$ExpandedPlayerSettingsCopyWith<$Res>? get expandedPlayerSettings {
|
||||
if (_value.expandedPlayerSettings == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $ExpandedPlayerSettingsCopyWith<$Res>(_value.expandedPlayerSettings!,
|
||||
(value) {
|
||||
return _then(_value.copyWith(expandedPlayerSettings: value) as $Val);
|
||||
});
|
||||
return $ExpandedPlayerSettingsCopyWith<$Res>(_self.expandedPlayerSettings!, (value) {
|
||||
return _then(_self.copyWith(expandedPlayerSettings: value));
|
||||
});
|
||||
}/// Create a copy of NullablePlayerSettings
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$SleepTimerSettingsCopyWith<$Res>? get sleepTimerSettings {
|
||||
if (_self.sleepTimerSettings == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/// Create a copy of NullablePlayerSettings
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$SleepTimerSettingsCopyWith<$Res>? get sleepTimerSettings {
|
||||
if (_value.sleepTimerSettings == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $SleepTimerSettingsCopyWith<$Res>(_value.sleepTimerSettings!,
|
||||
(value) {
|
||||
return _then(_value.copyWith(sleepTimerSettings: value) as $Val);
|
||||
});
|
||||
}
|
||||
return $SleepTimerSettingsCopyWith<$Res>(_self.sleepTimerSettings!, (value) {
|
||||
return _then(_self.copyWith(sleepTimerSettings: value));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$NullablePlayerSettingsImplCopyWith<$Res>
|
||||
implements $NullablePlayerSettingsCopyWith<$Res> {
|
||||
factory _$$NullablePlayerSettingsImplCopyWith(
|
||||
_$NullablePlayerSettingsImpl value,
|
||||
$Res Function(_$NullablePlayerSettingsImpl) then) =
|
||||
__$$NullablePlayerSettingsImplCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call(
|
||||
{MinimizedPlayerSettings? miniPlayerSettings,
|
||||
ExpandedPlayerSettings? expandedPlayerSettings,
|
||||
double? preferredDefaultVolume,
|
||||
double? preferredDefaultSpeed,
|
||||
List<double>? speedOptions,
|
||||
SleepTimerSettings? sleepTimerSettings,
|
||||
Duration? playbackReportInterval});
|
||||
|
||||
@override
|
||||
$MinimizedPlayerSettingsCopyWith<$Res>? get miniPlayerSettings;
|
||||
@override
|
||||
$ExpandedPlayerSettingsCopyWith<$Res>? get expandedPlayerSettings;
|
||||
@override
|
||||
$SleepTimerSettingsCopyWith<$Res>? get sleepTimerSettings;
|
||||
/// Adds pattern-matching-related methods to [NullablePlayerSettings].
|
||||
extension NullablePlayerSettingsPatterns on NullablePlayerSettings {
|
||||
/// A variant of `map` that fallback to returning `orElse`.
|
||||
///
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case final Subclass value:
|
||||
/// return ...;
|
||||
/// case _:
|
||||
/// return orElse();
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _NullablePlayerSettings value)? $default,{required TResult orElse(),}){
|
||||
final _that = this;
|
||||
switch (_that) {
|
||||
case _NullablePlayerSettings() when $default != null:
|
||||
return $default(_that);case _:
|
||||
return orElse();
|
||||
|
||||
}
|
||||
}
|
||||
/// A `switch`-like method, using callbacks.
|
||||
///
|
||||
/// Callbacks receives the raw object, upcasted.
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case final Subclass value:
|
||||
/// return ...;
|
||||
/// case final Subclass2 value:
|
||||
/// return ...;
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _NullablePlayerSettings value) $default,){
|
||||
final _that = this;
|
||||
switch (_that) {
|
||||
case _NullablePlayerSettings():
|
||||
return $default(_that);}
|
||||
}
|
||||
/// A variant of `map` that fallback to returning `null`.
|
||||
///
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case final Subclass value:
|
||||
/// return ...;
|
||||
/// case _:
|
||||
/// return null;
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _NullablePlayerSettings value)? $default,){
|
||||
final _that = this;
|
||||
switch (_that) {
|
||||
case _NullablePlayerSettings() when $default != null:
|
||||
return $default(_that);case _:
|
||||
return null;
|
||||
|
||||
}
|
||||
}
|
||||
/// A variant of `when` that fallback to an `orElse` callback.
|
||||
///
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case Subclass(:final field):
|
||||
/// return ...;
|
||||
/// case _:
|
||||
/// return orElse();
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( MinimizedPlayerSettings? miniPlayerSettings, ExpandedPlayerSettings? expandedPlayerSettings, double? preferredDefaultVolume, double? preferredDefaultSpeed, List<double>? speedOptions, SleepTimerSettings? sleepTimerSettings, Duration? playbackReportInterval)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
switch (_that) {
|
||||
case _NullablePlayerSettings() when $default != null:
|
||||
return $default(_that.miniPlayerSettings,_that.expandedPlayerSettings,_that.preferredDefaultVolume,_that.preferredDefaultSpeed,_that.speedOptions,_that.sleepTimerSettings,_that.playbackReportInterval);case _:
|
||||
return orElse();
|
||||
|
||||
}
|
||||
}
|
||||
/// A `switch`-like method, using callbacks.
|
||||
///
|
||||
/// As opposed to `map`, this offers destructuring.
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case Subclass(:final field):
|
||||
/// return ...;
|
||||
/// case Subclass2(:final field2):
|
||||
/// return ...;
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( MinimizedPlayerSettings? miniPlayerSettings, ExpandedPlayerSettings? expandedPlayerSettings, double? preferredDefaultVolume, double? preferredDefaultSpeed, List<double>? speedOptions, SleepTimerSettings? sleepTimerSettings, Duration? playbackReportInterval) $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _NullablePlayerSettings():
|
||||
return $default(_that.miniPlayerSettings,_that.expandedPlayerSettings,_that.preferredDefaultVolume,_that.preferredDefaultSpeed,_that.speedOptions,_that.sleepTimerSettings,_that.playbackReportInterval);}
|
||||
}
|
||||
/// A variant of `when` that fallback to returning `null`
|
||||
///
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case Subclass(:final field):
|
||||
/// return ...;
|
||||
/// case _:
|
||||
/// return null;
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( MinimizedPlayerSettings? miniPlayerSettings, ExpandedPlayerSettings? expandedPlayerSettings, double? preferredDefaultVolume, double? preferredDefaultSpeed, List<double>? speedOptions, SleepTimerSettings? sleepTimerSettings, Duration? playbackReportInterval)? $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _NullablePlayerSettings() when $default != null:
|
||||
return $default(_that.miniPlayerSettings,_that.expandedPlayerSettings,_that.preferredDefaultVolume,_that.preferredDefaultSpeed,_that.speedOptions,_that.sleepTimerSettings,_that.playbackReportInterval);case _:
|
||||
return null;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$NullablePlayerSettingsImplCopyWithImpl<$Res>
|
||||
extends _$NullablePlayerSettingsCopyWithImpl<$Res,
|
||||
_$NullablePlayerSettingsImpl>
|
||||
implements _$$NullablePlayerSettingsImplCopyWith<$Res> {
|
||||
__$$NullablePlayerSettingsImplCopyWithImpl(
|
||||
_$NullablePlayerSettingsImpl _value,
|
||||
$Res Function(_$NullablePlayerSettingsImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of NullablePlayerSettings
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? miniPlayerSettings = freezed,
|
||||
Object? expandedPlayerSettings = freezed,
|
||||
Object? preferredDefaultVolume = freezed,
|
||||
Object? preferredDefaultSpeed = freezed,
|
||||
Object? speedOptions = freezed,
|
||||
Object? sleepTimerSettings = freezed,
|
||||
Object? playbackReportInterval = freezed,
|
||||
}) {
|
||||
return _then(_$NullablePlayerSettingsImpl(
|
||||
miniPlayerSettings: freezed == miniPlayerSettings
|
||||
? _value.miniPlayerSettings
|
||||
: miniPlayerSettings // ignore: cast_nullable_to_non_nullable
|
||||
as MinimizedPlayerSettings?,
|
||||
expandedPlayerSettings: freezed == expandedPlayerSettings
|
||||
? _value.expandedPlayerSettings
|
||||
: expandedPlayerSettings // ignore: cast_nullable_to_non_nullable
|
||||
as ExpandedPlayerSettings?,
|
||||
preferredDefaultVolume: freezed == preferredDefaultVolume
|
||||
? _value.preferredDefaultVolume
|
||||
: preferredDefaultVolume // ignore: cast_nullable_to_non_nullable
|
||||
as double?,
|
||||
preferredDefaultSpeed: freezed == preferredDefaultSpeed
|
||||
? _value.preferredDefaultSpeed
|
||||
: preferredDefaultSpeed // ignore: cast_nullable_to_non_nullable
|
||||
as double?,
|
||||
speedOptions: freezed == speedOptions
|
||||
? _value._speedOptions
|
||||
: speedOptions // ignore: cast_nullable_to_non_nullable
|
||||
as List<double>?,
|
||||
sleepTimerSettings: freezed == sleepTimerSettings
|
||||
? _value.sleepTimerSettings
|
||||
: sleepTimerSettings // ignore: cast_nullable_to_non_nullable
|
||||
as SleepTimerSettings?,
|
||||
playbackReportInterval: freezed == playbackReportInterval
|
||||
? _value.playbackReportInterval
|
||||
: playbackReportInterval // ignore: cast_nullable_to_non_nullable
|
||||
as Duration?,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@JsonSerializable()
|
||||
class _$NullablePlayerSettingsImpl implements _NullablePlayerSettings {
|
||||
const _$NullablePlayerSettingsImpl(
|
||||
{this.miniPlayerSettings,
|
||||
this.expandedPlayerSettings,
|
||||
this.preferredDefaultVolume,
|
||||
this.preferredDefaultSpeed,
|
||||
final List<double>? speedOptions,
|
||||
this.sleepTimerSettings,
|
||||
this.playbackReportInterval})
|
||||
: _speedOptions = speedOptions;
|
||||
|
||||
factory _$NullablePlayerSettingsImpl.fromJson(Map<String, dynamic> json) =>
|
||||
_$$NullablePlayerSettingsImplFromJson(json);
|
||||
class _NullablePlayerSettings implements NullablePlayerSettings {
|
||||
const _NullablePlayerSettings({this.miniPlayerSettings, this.expandedPlayerSettings, this.preferredDefaultVolume, this.preferredDefaultSpeed, final List<double>? speedOptions, this.sleepTimerSettings, this.playbackReportInterval}): _speedOptions = speedOptions;
|
||||
factory _NullablePlayerSettings.fromJson(Map<String, dynamic> json) => _$NullablePlayerSettingsFromJson(json);
|
||||
|
||||
@override
|
||||
final MinimizedPlayerSettings? miniPlayerSettings;
|
||||
@override
|
||||
final ExpandedPlayerSettings? expandedPlayerSettings;
|
||||
@override
|
||||
final double? preferredDefaultVolume;
|
||||
@override
|
||||
final double? preferredDefaultSpeed;
|
||||
final List<double>? _speedOptions;
|
||||
@override
|
||||
List<double>? get speedOptions {
|
||||
final value = _speedOptions;
|
||||
if (value == null) return null;
|
||||
if (_speedOptions is EqualUnmodifiableListView) return _speedOptions;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableListView(value);
|
||||
}
|
||||
|
||||
@override
|
||||
final SleepTimerSettings? sleepTimerSettings;
|
||||
@override
|
||||
final Duration? playbackReportInterval;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'NullablePlayerSettings(miniPlayerSettings: $miniPlayerSettings, expandedPlayerSettings: $expandedPlayerSettings, preferredDefaultVolume: $preferredDefaultVolume, preferredDefaultSpeed: $preferredDefaultSpeed, speedOptions: $speedOptions, sleepTimerSettings: $sleepTimerSettings, playbackReportInterval: $playbackReportInterval)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$NullablePlayerSettingsImpl &&
|
||||
(identical(other.miniPlayerSettings, miniPlayerSettings) ||
|
||||
other.miniPlayerSettings == miniPlayerSettings) &&
|
||||
(identical(other.expandedPlayerSettings, expandedPlayerSettings) ||
|
||||
other.expandedPlayerSettings == expandedPlayerSettings) &&
|
||||
(identical(other.preferredDefaultVolume, preferredDefaultVolume) ||
|
||||
other.preferredDefaultVolume == preferredDefaultVolume) &&
|
||||
(identical(other.preferredDefaultSpeed, preferredDefaultSpeed) ||
|
||||
other.preferredDefaultSpeed == preferredDefaultSpeed) &&
|
||||
const DeepCollectionEquality()
|
||||
.equals(other._speedOptions, _speedOptions) &&
|
||||
(identical(other.sleepTimerSettings, sleepTimerSettings) ||
|
||||
other.sleepTimerSettings == sleepTimerSettings) &&
|
||||
(identical(other.playbackReportInterval, playbackReportInterval) ||
|
||||
other.playbackReportInterval == playbackReportInterval));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(
|
||||
runtimeType,
|
||||
miniPlayerSettings,
|
||||
expandedPlayerSettings,
|
||||
preferredDefaultVolume,
|
||||
preferredDefaultSpeed,
|
||||
const DeepCollectionEquality().hash(_speedOptions),
|
||||
sleepTimerSettings,
|
||||
playbackReportInterval);
|
||||
|
||||
/// Create a copy of NullablePlayerSettings
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$NullablePlayerSettingsImplCopyWith<_$NullablePlayerSettingsImpl>
|
||||
get copyWith => __$$NullablePlayerSettingsImplCopyWithImpl<
|
||||
_$NullablePlayerSettingsImpl>(this, _$identity);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return _$$NullablePlayerSettingsImplToJson(
|
||||
this,
|
||||
);
|
||||
}
|
||||
@override final MinimizedPlayerSettings? miniPlayerSettings;
|
||||
@override final ExpandedPlayerSettings? expandedPlayerSettings;
|
||||
@override final double? preferredDefaultVolume;
|
||||
@override final double? preferredDefaultSpeed;
|
||||
final List<double>? _speedOptions;
|
||||
@override List<double>? get speedOptions {
|
||||
final value = _speedOptions;
|
||||
if (value == null) return null;
|
||||
if (_speedOptions is EqualUnmodifiableListView) return _speedOptions;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableListView(value);
|
||||
}
|
||||
|
||||
abstract class _NullablePlayerSettings implements NullablePlayerSettings {
|
||||
const factory _NullablePlayerSettings(
|
||||
{final MinimizedPlayerSettings? miniPlayerSettings,
|
||||
final ExpandedPlayerSettings? expandedPlayerSettings,
|
||||
final double? preferredDefaultVolume,
|
||||
final double? preferredDefaultSpeed,
|
||||
final List<double>? speedOptions,
|
||||
final SleepTimerSettings? sleepTimerSettings,
|
||||
final Duration? playbackReportInterval}) = _$NullablePlayerSettingsImpl;
|
||||
@override final SleepTimerSettings? sleepTimerSettings;
|
||||
@override final Duration? playbackReportInterval;
|
||||
|
||||
factory _NullablePlayerSettings.fromJson(Map<String, dynamic> json) =
|
||||
_$NullablePlayerSettingsImpl.fromJson;
|
||||
/// Create a copy of NullablePlayerSettings
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
_$NullablePlayerSettingsCopyWith<_NullablePlayerSettings> get copyWith => __$NullablePlayerSettingsCopyWithImpl<_NullablePlayerSettings>(this, _$identity);
|
||||
|
||||
@override
|
||||
MinimizedPlayerSettings? get miniPlayerSettings;
|
||||
@override
|
||||
ExpandedPlayerSettings? get expandedPlayerSettings;
|
||||
@override
|
||||
double? get preferredDefaultVolume;
|
||||
@override
|
||||
double? get preferredDefaultSpeed;
|
||||
@override
|
||||
List<double>? get speedOptions;
|
||||
@override
|
||||
SleepTimerSettings? get sleepTimerSettings;
|
||||
@override
|
||||
Duration? get playbackReportInterval;
|
||||
|
||||
/// Create a copy of NullablePlayerSettings
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$NullablePlayerSettingsImplCopyWith<_$NullablePlayerSettingsImpl>
|
||||
get copyWith => throw _privateConstructorUsedError;
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return _$NullablePlayerSettingsToJson(this, );
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _NullablePlayerSettings&&(identical(other.miniPlayerSettings, miniPlayerSettings) || other.miniPlayerSettings == miniPlayerSettings)&&(identical(other.expandedPlayerSettings, expandedPlayerSettings) || other.expandedPlayerSettings == expandedPlayerSettings)&&(identical(other.preferredDefaultVolume, preferredDefaultVolume) || other.preferredDefaultVolume == preferredDefaultVolume)&&(identical(other.preferredDefaultSpeed, preferredDefaultSpeed) || other.preferredDefaultSpeed == preferredDefaultSpeed)&&const DeepCollectionEquality().equals(other._speedOptions, _speedOptions)&&(identical(other.sleepTimerSettings, sleepTimerSettings) || other.sleepTimerSettings == sleepTimerSettings)&&(identical(other.playbackReportInterval, playbackReportInterval) || other.playbackReportInterval == playbackReportInterval));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,miniPlayerSettings,expandedPlayerSettings,preferredDefaultVolume,preferredDefaultSpeed,const DeepCollectionEquality().hash(_speedOptions),sleepTimerSettings,playbackReportInterval);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'NullablePlayerSettings(miniPlayerSettings: $miniPlayerSettings, expandedPlayerSettings: $expandedPlayerSettings, preferredDefaultVolume: $preferredDefaultVolume, preferredDefaultSpeed: $preferredDefaultSpeed, speedOptions: $speedOptions, sleepTimerSettings: $sleepTimerSettings, playbackReportInterval: $playbackReportInterval)';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class _$NullablePlayerSettingsCopyWith<$Res> implements $NullablePlayerSettingsCopyWith<$Res> {
|
||||
factory _$NullablePlayerSettingsCopyWith(_NullablePlayerSettings value, $Res Function(_NullablePlayerSettings) _then) = __$NullablePlayerSettingsCopyWithImpl;
|
||||
@override @useResult
|
||||
$Res call({
|
||||
MinimizedPlayerSettings? miniPlayerSettings, ExpandedPlayerSettings? expandedPlayerSettings, double? preferredDefaultVolume, double? preferredDefaultSpeed, List<double>? speedOptions, SleepTimerSettings? sleepTimerSettings, Duration? playbackReportInterval
|
||||
});
|
||||
|
||||
|
||||
@override $MinimizedPlayerSettingsCopyWith<$Res>? get miniPlayerSettings;@override $ExpandedPlayerSettingsCopyWith<$Res>? get expandedPlayerSettings;@override $SleepTimerSettingsCopyWith<$Res>? get sleepTimerSettings;
|
||||
|
||||
}
|
||||
/// @nodoc
|
||||
class __$NullablePlayerSettingsCopyWithImpl<$Res>
|
||||
implements _$NullablePlayerSettingsCopyWith<$Res> {
|
||||
__$NullablePlayerSettingsCopyWithImpl(this._self, this._then);
|
||||
|
||||
final _NullablePlayerSettings _self;
|
||||
final $Res Function(_NullablePlayerSettings) _then;
|
||||
|
||||
/// Create a copy of NullablePlayerSettings
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? miniPlayerSettings = freezed,Object? expandedPlayerSettings = freezed,Object? preferredDefaultVolume = freezed,Object? preferredDefaultSpeed = freezed,Object? speedOptions = freezed,Object? sleepTimerSettings = freezed,Object? playbackReportInterval = freezed,}) {
|
||||
return _then(_NullablePlayerSettings(
|
||||
miniPlayerSettings: freezed == miniPlayerSettings ? _self.miniPlayerSettings : miniPlayerSettings // ignore: cast_nullable_to_non_nullable
|
||||
as MinimizedPlayerSettings?,expandedPlayerSettings: freezed == expandedPlayerSettings ? _self.expandedPlayerSettings : expandedPlayerSettings // ignore: cast_nullable_to_non_nullable
|
||||
as ExpandedPlayerSettings?,preferredDefaultVolume: freezed == preferredDefaultVolume ? _self.preferredDefaultVolume : preferredDefaultVolume // ignore: cast_nullable_to_non_nullable
|
||||
as double?,preferredDefaultSpeed: freezed == preferredDefaultSpeed ? _self.preferredDefaultSpeed : preferredDefaultSpeed // ignore: cast_nullable_to_non_nullable
|
||||
as double?,speedOptions: freezed == speedOptions ? _self._speedOptions : speedOptions // ignore: cast_nullable_to_non_nullable
|
||||
as List<double>?,sleepTimerSettings: freezed == sleepTimerSettings ? _self.sleepTimerSettings : sleepTimerSettings // ignore: cast_nullable_to_non_nullable
|
||||
as SleepTimerSettings?,playbackReportInterval: freezed == playbackReportInterval ? _self.playbackReportInterval : playbackReportInterval // ignore: cast_nullable_to_non_nullable
|
||||
as Duration?,
|
||||
));
|
||||
}
|
||||
|
||||
/// Create a copy of NullablePlayerSettings
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$MinimizedPlayerSettingsCopyWith<$Res>? get miniPlayerSettings {
|
||||
if (_self.miniPlayerSettings == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $MinimizedPlayerSettingsCopyWith<$Res>(_self.miniPlayerSettings!, (value) {
|
||||
return _then(_self.copyWith(miniPlayerSettings: value));
|
||||
});
|
||||
}/// Create a copy of NullablePlayerSettings
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$ExpandedPlayerSettingsCopyWith<$Res>? get expandedPlayerSettings {
|
||||
if (_self.expandedPlayerSettings == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $ExpandedPlayerSettingsCopyWith<$Res>(_self.expandedPlayerSettings!, (value) {
|
||||
return _then(_self.copyWith(expandedPlayerSettings: value));
|
||||
});
|
||||
}/// Create a copy of NullablePlayerSettings
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$SleepTimerSettingsCopyWith<$Res>? get sleepTimerSettings {
|
||||
if (_self.sleepTimerSettings == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $SleepTimerSettingsCopyWith<$Res>(_self.sleepTimerSettings!, (value) {
|
||||
return _then(_self.copyWith(sleepTimerSettings: value));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// dart format on
|
||||
|
|
|
|||
|
|
@ -6,42 +6,42 @@ part of 'nullable_player_settings.dart';
|
|||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
_$NullablePlayerSettingsImpl _$$NullablePlayerSettingsImplFromJson(
|
||||
Map<String, dynamic> json) =>
|
||||
_$NullablePlayerSettingsImpl(
|
||||
miniPlayerSettings: json['miniPlayerSettings'] == null
|
||||
? null
|
||||
: MinimizedPlayerSettings.fromJson(
|
||||
json['miniPlayerSettings'] as Map<String, dynamic>),
|
||||
expandedPlayerSettings: json['expandedPlayerSettings'] == null
|
||||
? null
|
||||
: ExpandedPlayerSettings.fromJson(
|
||||
json['expandedPlayerSettings'] as Map<String, dynamic>),
|
||||
preferredDefaultVolume:
|
||||
(json['preferredDefaultVolume'] as num?)?.toDouble(),
|
||||
preferredDefaultSpeed:
|
||||
(json['preferredDefaultSpeed'] as num?)?.toDouble(),
|
||||
speedOptions: (json['speedOptions'] as List<dynamic>?)
|
||||
?.map((e) => (e as num).toDouble())
|
||||
.toList(),
|
||||
sleepTimerSettings: json['sleepTimerSettings'] == null
|
||||
? null
|
||||
: SleepTimerSettings.fromJson(
|
||||
json['sleepTimerSettings'] as Map<String, dynamic>),
|
||||
playbackReportInterval: json['playbackReportInterval'] == null
|
||||
? null
|
||||
: Duration(
|
||||
microseconds: (json['playbackReportInterval'] as num).toInt()),
|
||||
);
|
||||
_NullablePlayerSettings _$NullablePlayerSettingsFromJson(
|
||||
Map<String, dynamic> json,
|
||||
) => _NullablePlayerSettings(
|
||||
miniPlayerSettings: json['miniPlayerSettings'] == null
|
||||
? null
|
||||
: MinimizedPlayerSettings.fromJson(
|
||||
json['miniPlayerSettings'] as Map<String, dynamic>,
|
||||
),
|
||||
expandedPlayerSettings: json['expandedPlayerSettings'] == null
|
||||
? null
|
||||
: ExpandedPlayerSettings.fromJson(
|
||||
json['expandedPlayerSettings'] as Map<String, dynamic>,
|
||||
),
|
||||
preferredDefaultVolume: (json['preferredDefaultVolume'] as num?)?.toDouble(),
|
||||
preferredDefaultSpeed: (json['preferredDefaultSpeed'] as num?)?.toDouble(),
|
||||
speedOptions: (json['speedOptions'] as List<dynamic>?)
|
||||
?.map((e) => (e as num).toDouble())
|
||||
.toList(),
|
||||
sleepTimerSettings: json['sleepTimerSettings'] == null
|
||||
? null
|
||||
: SleepTimerSettings.fromJson(
|
||||
json['sleepTimerSettings'] as Map<String, dynamic>,
|
||||
),
|
||||
playbackReportInterval: json['playbackReportInterval'] == null
|
||||
? null
|
||||
: Duration(microseconds: (json['playbackReportInterval'] as num).toInt()),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$NullablePlayerSettingsImplToJson(
|
||||
_$NullablePlayerSettingsImpl instance) =>
|
||||
<String, dynamic>{
|
||||
'miniPlayerSettings': instance.miniPlayerSettings,
|
||||
'expandedPlayerSettings': instance.expandedPlayerSettings,
|
||||
'preferredDefaultVolume': instance.preferredDefaultVolume,
|
||||
'preferredDefaultSpeed': instance.preferredDefaultSpeed,
|
||||
'speedOptions': instance.speedOptions,
|
||||
'sleepTimerSettings': instance.sleepTimerSettings,
|
||||
'playbackReportInterval': instance.playbackReportInterval?.inMicroseconds,
|
||||
};
|
||||
Map<String, dynamic> _$NullablePlayerSettingsToJson(
|
||||
_NullablePlayerSettings instance,
|
||||
) => <String, dynamic>{
|
||||
'miniPlayerSettings': instance.miniPlayerSettings,
|
||||
'expandedPlayerSettings': instance.expandedPlayerSettings,
|
||||
'preferredDefaultVolume': instance.preferredDefaultVolume,
|
||||
'preferredDefaultSpeed': instance.preferredDefaultSpeed,
|
||||
'speedOptions': instance.speedOptions,
|
||||
'sleepTimerSettings': instance.sleepTimerSettings,
|
||||
'playbackReportInterval': instance.playbackReportInterval?.inMicroseconds,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -6,171 +6,102 @@ part of 'book_settings_provider.dart';
|
|||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$bookSettingsHash() => r'b976df954edf98ec6ccb3eb41e9d07dd4a9193eb';
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
_SystemHash._();
|
||||
|
||||
static int combine(int hash, int value) {
|
||||
// ignore: parameter_assignments
|
||||
hash = 0x1fffffff & (hash + value);
|
||||
// ignore: parameter_assignments
|
||||
hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
|
||||
return hash ^ (hash >> 6);
|
||||
}
|
||||
|
||||
static int finish(int hash) {
|
||||
// ignore: parameter_assignments
|
||||
hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
|
||||
// ignore: parameter_assignments
|
||||
hash = hash ^ (hash >> 11);
|
||||
return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _$BookSettings
|
||||
extends BuildlessAutoDisposeNotifier<model.BookSettings> {
|
||||
late final String bookId;
|
||||
|
||||
model.BookSettings build(
|
||||
String bookId,
|
||||
);
|
||||
}
|
||||
|
||||
/// See also [BookSettings].
|
||||
@ProviderFor(BookSettings)
|
||||
const bookSettingsProvider = BookSettingsFamily();
|
||||
final bookSettingsProvider = BookSettingsFamily._();
|
||||
|
||||
/// See also [BookSettings].
|
||||
class BookSettingsFamily extends Family<model.BookSettings> {
|
||||
/// See also [BookSettings].
|
||||
const BookSettingsFamily();
|
||||
final class BookSettingsProvider
|
||||
extends $NotifierProvider<BookSettings, model.BookSettings> {
|
||||
BookSettingsProvider._({
|
||||
required BookSettingsFamily super.from,
|
||||
required String super.argument,
|
||||
}) : super(
|
||||
retry: null,
|
||||
name: r'bookSettingsProvider',
|
||||
isAutoDispose: true,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
/// See also [BookSettings].
|
||||
BookSettingsProvider call(
|
||||
String bookId,
|
||||
) {
|
||||
return BookSettingsProvider(
|
||||
bookId,
|
||||
);
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$bookSettingsHash();
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return r'bookSettingsProvider'
|
||||
''
|
||||
'($argument)';
|
||||
}
|
||||
|
||||
@$internal
|
||||
@override
|
||||
BookSettingsProvider getProviderOverride(
|
||||
covariant BookSettingsProvider provider,
|
||||
) {
|
||||
return call(
|
||||
provider.bookId,
|
||||
);
|
||||
}
|
||||
BookSettings create() => BookSettings();
|
||||
|
||||
static const Iterable<ProviderOrFamily>? _dependencies = null;
|
||||
|
||||
@override
|
||||
Iterable<ProviderOrFamily>? get dependencies => _dependencies;
|
||||
|
||||
static const Iterable<ProviderOrFamily>? _allTransitiveDependencies = null;
|
||||
|
||||
@override
|
||||
Iterable<ProviderOrFamily>? get allTransitiveDependencies =>
|
||||
_allTransitiveDependencies;
|
||||
|
||||
@override
|
||||
String? get name => r'bookSettingsProvider';
|
||||
}
|
||||
|
||||
/// See also [BookSettings].
|
||||
class BookSettingsProvider
|
||||
extends AutoDisposeNotifierProviderImpl<BookSettings, model.BookSettings> {
|
||||
/// See also [BookSettings].
|
||||
BookSettingsProvider(
|
||||
String bookId,
|
||||
) : this._internal(
|
||||
() => BookSettings()..bookId = bookId,
|
||||
from: bookSettingsProvider,
|
||||
name: r'bookSettingsProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$bookSettingsHash,
|
||||
dependencies: BookSettingsFamily._dependencies,
|
||||
allTransitiveDependencies:
|
||||
BookSettingsFamily._allTransitiveDependencies,
|
||||
bookId: bookId,
|
||||
);
|
||||
|
||||
BookSettingsProvider._internal(
|
||||
super._createNotifier, {
|
||||
required super.name,
|
||||
required super.dependencies,
|
||||
required super.allTransitiveDependencies,
|
||||
required super.debugGetCreateSourceHash,
|
||||
required super.from,
|
||||
required this.bookId,
|
||||
}) : super.internal();
|
||||
|
||||
final String bookId;
|
||||
|
||||
@override
|
||||
model.BookSettings runNotifierBuild(
|
||||
covariant BookSettings notifier,
|
||||
) {
|
||||
return notifier.build(
|
||||
bookId,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Override overrideWith(BookSettings Function() create) {
|
||||
return ProviderOverride(
|
||||
/// {@macro riverpod.override_with_value}
|
||||
Override overrideWithValue(model.BookSettings value) {
|
||||
return $ProviderOverride(
|
||||
origin: this,
|
||||
override: BookSettingsProvider._internal(
|
||||
() => create()..bookId = bookId,
|
||||
from: from,
|
||||
name: null,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
debugGetCreateSourceHash: null,
|
||||
bookId: bookId,
|
||||
),
|
||||
providerOverride: $SyncValueProvider<model.BookSettings>(value),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
AutoDisposeNotifierProviderElement<BookSettings, model.BookSettings>
|
||||
createElement() {
|
||||
return _BookSettingsProviderElement(this);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is BookSettingsProvider && other.bookId == bookId;
|
||||
return other is BookSettingsProvider && other.argument == argument;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
||||
hash = _SystemHash.combine(hash, bookId.hashCode);
|
||||
|
||||
return _SystemHash.finish(hash);
|
||||
return argument.hashCode;
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||
// ignore: unused_element
|
||||
mixin BookSettingsRef on AutoDisposeNotifierProviderRef<model.BookSettings> {
|
||||
/// The parameter `bookId` of this provider.
|
||||
String get bookId;
|
||||
}
|
||||
String _$bookSettingsHash() => r'b976df954edf98ec6ccb3eb41e9d07dd4a9193eb';
|
||||
|
||||
class _BookSettingsProviderElement
|
||||
extends AutoDisposeNotifierProviderElement<BookSettings, model.BookSettings>
|
||||
with BookSettingsRef {
|
||||
_BookSettingsProviderElement(super.provider);
|
||||
final class BookSettingsFamily extends $Family
|
||||
with
|
||||
$ClassFamilyOverride<
|
||||
BookSettings,
|
||||
model.BookSettings,
|
||||
model.BookSettings,
|
||||
model.BookSettings,
|
||||
String
|
||||
> {
|
||||
BookSettingsFamily._()
|
||||
: super(
|
||||
retry: null,
|
||||
name: r'bookSettingsProvider',
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
isAutoDispose: true,
|
||||
);
|
||||
|
||||
BookSettingsProvider call(String bookId) =>
|
||||
BookSettingsProvider._(argument: bookId, from: this);
|
||||
|
||||
@override
|
||||
String get bookId => (origin as BookSettingsProvider).bookId;
|
||||
String toString() => r'bookSettingsProvider';
|
||||
}
|
||||
|
||||
abstract class _$BookSettings extends $Notifier<model.BookSettings> {
|
||||
late final _$args = ref.$arg as String;
|
||||
String get bookId => _$args;
|
||||
|
||||
model.BookSettings build(String bookId);
|
||||
@$mustCallSuper
|
||||
@override
|
||||
void runBuild() {
|
||||
final ref = this.ref as $Ref<model.BookSettings, model.BookSettings>;
|
||||
final element =
|
||||
ref.element
|
||||
as $ClassProviderElement<
|
||||
AnyNotifier<model.BookSettings, model.BookSettings>,
|
||||
model.BookSettings,
|
||||
Object?,
|
||||
Object?
|
||||
>;
|
||||
element.handleCreate(ref, () => build(_$args));
|
||||
}
|
||||
}
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package
|
||||
|
|
|
|||
|
|
@ -126,9 +126,7 @@ class PlaybackReporter {
|
|||
}
|
||||
|
||||
Future<void> tryReportPlayback(_) async {
|
||||
_logger.fine(
|
||||
'callback called when elapsed ${_stopwatch.elapsed}',
|
||||
);
|
||||
_logger.fine('callback called when elapsed ${_stopwatch.elapsed}');
|
||||
if (player.book != null &&
|
||||
player.positionInBook >=
|
||||
player.book!.duration - markCompleteWhenTimeLeft) {
|
||||
|
|
|
|||
|
|
@ -20,8 +20,9 @@ class PlaybackReporter extends _$PlaybackReporter {
|
|||
final deviceName = await ref.watch(deviceNameProvider.future);
|
||||
final deviceModel = await ref.watch(deviceModelProvider.future);
|
||||
final deviceSdkVersion = await ref.watch(deviceSdkVersionProvider.future);
|
||||
final deviceManufacturer =
|
||||
await ref.watch(deviceManufacturerProvider.future);
|
||||
final deviceManufacturer = await ref.watch(
|
||||
deviceManufacturerProvider.future,
|
||||
);
|
||||
|
||||
final reporter = core.PlaybackReporter(
|
||||
player,
|
||||
|
|
|
|||
|
|
@ -6,21 +6,55 @@ part of 'playback_reporter_provider.dart';
|
|||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
|
||||
@ProviderFor(PlaybackReporter)
|
||||
final playbackReporterProvider = PlaybackReporterProvider._();
|
||||
|
||||
final class PlaybackReporterProvider
|
||||
extends $AsyncNotifierProvider<PlaybackReporter, core.PlaybackReporter> {
|
||||
PlaybackReporterProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
retry: null,
|
||||
name: r'playbackReporterProvider',
|
||||
isAutoDispose: false,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$playbackReporterHash();
|
||||
|
||||
@$internal
|
||||
@override
|
||||
PlaybackReporter create() => PlaybackReporter();
|
||||
}
|
||||
|
||||
String _$playbackReporterHash() => r'f5436d652e51c37bcc684acdaec94e17a97e68e5';
|
||||
|
||||
/// See also [PlaybackReporter].
|
||||
@ProviderFor(PlaybackReporter)
|
||||
final playbackReporterProvider =
|
||||
AsyncNotifierProvider<PlaybackReporter, core.PlaybackReporter>.internal(
|
||||
PlaybackReporter.new,
|
||||
name: r'playbackReporterProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$playbackReporterHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
typedef _$PlaybackReporter = AsyncNotifier<core.PlaybackReporter>;
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package
|
||||
abstract class _$PlaybackReporter
|
||||
extends $AsyncNotifier<core.PlaybackReporter> {
|
||||
FutureOr<core.PlaybackReporter> build();
|
||||
@$mustCallSuper
|
||||
@override
|
||||
void runBuild() {
|
||||
final ref =
|
||||
this.ref
|
||||
as $Ref<AsyncValue<core.PlaybackReporter>, core.PlaybackReporter>;
|
||||
final element =
|
||||
ref.element
|
||||
as $ClassProviderElement<
|
||||
AnyNotifier<
|
||||
AsyncValue<core.PlaybackReporter>,
|
||||
core.PlaybackReporter
|
||||
>,
|
||||
AsyncValue<core.PlaybackReporter>,
|
||||
Object?,
|
||||
Object?
|
||||
>;
|
||||
element.handleCreate(ref, build);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,9 @@ Duration sumOfTracks(BookExpanded book, int? index) {
|
|||
_logger.warning('Index is null or less than 0, returning 0');
|
||||
return Duration.zero;
|
||||
}
|
||||
final total = book.tracks.sublist(0, index).fold<Duration>(
|
||||
final total = book.tracks
|
||||
.sublist(0, index)
|
||||
.fold<Duration>(
|
||||
Duration.zero,
|
||||
(previousValue, element) => previousValue + element.duration,
|
||||
);
|
||||
|
|
@ -34,13 +36,10 @@ Duration sumOfTracks(BookExpanded book, int? index) {
|
|||
/// returns the [AudioTrack] to play based on the [position] in the [book]
|
||||
AudioTrack getTrackToPlay(BookExpanded book, Duration position) {
|
||||
_logger.fine('Getting track to play for position: $position');
|
||||
final track = book.tracks.firstWhere(
|
||||
(element) {
|
||||
return element.startOffset <= position &&
|
||||
(element.startOffset + element.duration) >= position;
|
||||
},
|
||||
orElse: () => book.tracks.last,
|
||||
);
|
||||
final track = book.tracks.firstWhere((element) {
|
||||
return element.startOffset <= position &&
|
||||
(element.startOffset + element.duration) >= position;
|
||||
}, orElse: () => book.tracks.last);
|
||||
_logger.fine('Track to play for position: $position is $track');
|
||||
return track;
|
||||
}
|
||||
|
|
@ -126,8 +125,12 @@ class AudiobookPlayer extends AudioPlayer {
|
|||
ConcatenatingAudioSource(
|
||||
useLazyPreparation: true,
|
||||
children: book.tracks.map((track) {
|
||||
final retrievedUri =
|
||||
_getUri(track, downloadedUris, baseUrl: baseUrl, token: token);
|
||||
final retrievedUri = _getUri(
|
||||
track,
|
||||
downloadedUris,
|
||||
baseUrl: baseUrl,
|
||||
token: token,
|
||||
);
|
||||
_logger.fine(
|
||||
'Setting source for track: ${track.title}, URI: ${retrievedUri.obfuscate()}',
|
||||
);
|
||||
|
|
@ -141,7 +144,8 @@ class AudiobookPlayer extends AudioPlayer {
|
|||
.formatNotificationTitle(book),
|
||||
album: appSettings.notificationSettings.secondaryTitle
|
||||
.formatNotificationTitle(book),
|
||||
artUri: artworkUri ??
|
||||
artUri:
|
||||
artworkUri ??
|
||||
Uri.parse(
|
||||
'$baseUrl/api/items/${book.libraryItemId}/cover?token=$token&width=800',
|
||||
),
|
||||
|
|
@ -255,12 +259,9 @@ class AudiobookPlayer extends AudioPlayer {
|
|||
if (_book!.chapters.isEmpty) {
|
||||
return null;
|
||||
}
|
||||
return _book!.chapters.firstWhere(
|
||||
(element) {
|
||||
return element.start <= positionInBook && element.end >= positionInBook;
|
||||
},
|
||||
orElse: () => _book!.chapters.first,
|
||||
);
|
||||
return _book!.chapters.firstWhere((element) {
|
||||
return element.start <= positionInBook && element.end >= positionInBook;
|
||||
}, orElse: () => _book!.chapters.first);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -271,11 +272,9 @@ Uri _getUri(
|
|||
required String token,
|
||||
}) {
|
||||
// check if the track is in the downloadedUris
|
||||
final uri = downloadedUris?.firstWhereOrNull(
|
||||
(element) {
|
||||
return element.pathSegments.last == track.metadata?.filename;
|
||||
},
|
||||
);
|
||||
final uri = downloadedUris?.firstWhereOrNull((element) {
|
||||
return element.pathSegments.last == track.metadata?.filename;
|
||||
});
|
||||
|
||||
return uri ??
|
||||
Uri.parse('${baseUrl.toString()}${track.contentUrl}?token=$token');
|
||||
|
|
@ -283,17 +282,14 @@ Uri _getUri(
|
|||
|
||||
extension FormatNotificationTitle on String {
|
||||
String formatNotificationTitle(BookExpanded book) {
|
||||
return replaceAllMapped(
|
||||
RegExp(r'\$(\w+)'),
|
||||
(match) {
|
||||
final type = match.group(1);
|
||||
return NotificationTitleType.values
|
||||
.firstWhere((element) => element.name == type)
|
||||
.extractFrom(book) ??
|
||||
match.group(0) ??
|
||||
'';
|
||||
},
|
||||
);
|
||||
return replaceAllMapped(RegExp(r'\$(\w+)'), (match) {
|
||||
final type = match.group(1);
|
||||
return NotificationTitleType.values
|
||||
.firstWhere((element) => element.name == type)
|
||||
.extractFrom(book) ??
|
||||
match.group(0) ??
|
||||
'';
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -30,23 +30,28 @@ Future<void> configurePlayer() async {
|
|||
androidShowNotificationBadge: false,
|
||||
notificationConfigBuilder: (state) {
|
||||
final controls = [
|
||||
if (appSettings.notificationSettings.mediaControls
|
||||
.contains(NotificationMediaControl.skipToPreviousChapter) &&
|
||||
if (appSettings.notificationSettings.mediaControls.contains(
|
||||
NotificationMediaControl.skipToPreviousChapter,
|
||||
) &&
|
||||
state.hasPrevious)
|
||||
MediaControl.skipToPrevious,
|
||||
if (appSettings.notificationSettings.mediaControls
|
||||
.contains(NotificationMediaControl.rewind))
|
||||
if (appSettings.notificationSettings.mediaControls.contains(
|
||||
NotificationMediaControl.rewind,
|
||||
))
|
||||
MediaControl.rewind,
|
||||
if (state.playing) MediaControl.pause else MediaControl.play,
|
||||
if (appSettings.notificationSettings.mediaControls
|
||||
.contains(NotificationMediaControl.fastForward))
|
||||
if (appSettings.notificationSettings.mediaControls.contains(
|
||||
NotificationMediaControl.fastForward,
|
||||
))
|
||||
MediaControl.fastForward,
|
||||
if (appSettings.notificationSettings.mediaControls
|
||||
.contains(NotificationMediaControl.skipToNextChapter) &&
|
||||
if (appSettings.notificationSettings.mediaControls.contains(
|
||||
NotificationMediaControl.skipToNextChapter,
|
||||
) &&
|
||||
state.hasNext)
|
||||
MediaControl.skipToNext,
|
||||
if (appSettings.notificationSettings.mediaControls
|
||||
.contains(NotificationMediaControl.stop))
|
||||
if (appSettings.notificationSettings.mediaControls.contains(
|
||||
NotificationMediaControl.stop,
|
||||
))
|
||||
MediaControl.stop,
|
||||
];
|
||||
return NotificationConfig(
|
||||
|
|
|
|||
|
|
@ -62,8 +62,8 @@ class AudiobookPlaylist {
|
|||
this.books = const [],
|
||||
currentIndex = 0,
|
||||
subCurrentIndex = 0,
|
||||
}) : _currentIndex = currentIndex,
|
||||
_subCurrentIndex = subCurrentIndex;
|
||||
}) : _currentIndex = currentIndex,
|
||||
_subCurrentIndex = subCurrentIndex;
|
||||
|
||||
// most important method, gets the audio file to play
|
||||
// this is needed as a library item is a list of audio files
|
||||
|
|
|
|||
|
|
@ -6,20 +6,57 @@ part of 'playlist_provider.dart';
|
|||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
|
||||
@ProviderFor(Playlist)
|
||||
final playlistProvider = PlaylistProvider._();
|
||||
|
||||
final class PlaylistProvider
|
||||
extends $NotifierProvider<Playlist, AudiobookPlaylist> {
|
||||
PlaylistProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
retry: null,
|
||||
name: r'playlistProvider',
|
||||
isAutoDispose: true,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$playlistHash();
|
||||
|
||||
@$internal
|
||||
@override
|
||||
Playlist create() => Playlist();
|
||||
|
||||
/// {@macro riverpod.override_with_value}
|
||||
Override overrideWithValue(AudiobookPlaylist value) {
|
||||
return $ProviderOverride(
|
||||
origin: this,
|
||||
providerOverride: $SyncValueProvider<AudiobookPlaylist>(value),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
String _$playlistHash() => r'bed4642e4c2de829e4d0630cb5bf92bffeeb1f60';
|
||||
|
||||
/// See also [Playlist].
|
||||
@ProviderFor(Playlist)
|
||||
final playlistProvider =
|
||||
AutoDisposeNotifierProvider<Playlist, AudiobookPlaylist>.internal(
|
||||
Playlist.new,
|
||||
name: r'playlistProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product') ? null : _$playlistHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
typedef _$Playlist = AutoDisposeNotifier<AudiobookPlaylist>;
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package
|
||||
abstract class _$Playlist extends $Notifier<AudiobookPlaylist> {
|
||||
AudiobookPlaylist build();
|
||||
@$mustCallSuper
|
||||
@override
|
||||
void runBuild() {
|
||||
final ref = this.ref as $Ref<AudiobookPlaylist, AudiobookPlaylist>;
|
||||
final element =
|
||||
ref.element
|
||||
as $ClassProviderElement<
|
||||
AnyNotifier<AudiobookPlaylist, AudiobookPlaylist>,
|
||||
AudiobookPlaylist,
|
||||
Object?,
|
||||
Object?
|
||||
>;
|
||||
element.handleCreate(ref, build);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,10 +16,7 @@ class SimpleAudiobookPlayer extends _$SimpleAudiobookPlayer {
|
|||
@override
|
||||
core.AudiobookPlayer build() {
|
||||
final api = ref.watch(authenticatedApiProvider);
|
||||
final player = core.AudiobookPlayer(
|
||||
api.token!,
|
||||
api.baseUrl,
|
||||
);
|
||||
final player = core.AudiobookPlayer(api.token!, api.baseUrl);
|
||||
|
||||
ref.onDispose(player.dispose);
|
||||
_logger.finer('created simple player');
|
||||
|
|
|
|||
|
|
@ -6,41 +6,119 @@ part of 'audiobook_player.dart';
|
|||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
/// Simple because it doesn't rebuild when the player state changes
|
||||
/// it only rebuilds when the token changes
|
||||
|
||||
@ProviderFor(SimpleAudiobookPlayer)
|
||||
final simpleAudiobookPlayerProvider = SimpleAudiobookPlayerProvider._();
|
||||
|
||||
/// Simple because it doesn't rebuild when the player state changes
|
||||
/// it only rebuilds when the token changes
|
||||
final class SimpleAudiobookPlayerProvider
|
||||
extends $NotifierProvider<SimpleAudiobookPlayer, core.AudiobookPlayer> {
|
||||
/// Simple because it doesn't rebuild when the player state changes
|
||||
/// it only rebuilds when the token changes
|
||||
SimpleAudiobookPlayerProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
retry: null,
|
||||
name: r'simpleAudiobookPlayerProvider',
|
||||
isAutoDispose: false,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$simpleAudiobookPlayerHash();
|
||||
|
||||
@$internal
|
||||
@override
|
||||
SimpleAudiobookPlayer create() => SimpleAudiobookPlayer();
|
||||
|
||||
/// {@macro riverpod.override_with_value}
|
||||
Override overrideWithValue(core.AudiobookPlayer value) {
|
||||
return $ProviderOverride(
|
||||
origin: this,
|
||||
providerOverride: $SyncValueProvider<core.AudiobookPlayer>(value),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
String _$simpleAudiobookPlayerHash() =>
|
||||
r'5e94bbff4314adceb5affa704fc4d079d4016afa';
|
||||
|
||||
/// Simple because it doesn't rebuild when the player state changes
|
||||
/// it only rebuilds when the token changes
|
||||
///
|
||||
/// Copied from [SimpleAudiobookPlayer].
|
||||
@ProviderFor(SimpleAudiobookPlayer)
|
||||
final simpleAudiobookPlayerProvider =
|
||||
NotifierProvider<SimpleAudiobookPlayer, core.AudiobookPlayer>.internal(
|
||||
SimpleAudiobookPlayer.new,
|
||||
name: r'simpleAudiobookPlayerProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$simpleAudiobookPlayerHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
typedef _$SimpleAudiobookPlayer = Notifier<core.AudiobookPlayer>;
|
||||
abstract class _$SimpleAudiobookPlayer extends $Notifier<core.AudiobookPlayer> {
|
||||
core.AudiobookPlayer build();
|
||||
@$mustCallSuper
|
||||
@override
|
||||
void runBuild() {
|
||||
final ref = this.ref as $Ref<core.AudiobookPlayer, core.AudiobookPlayer>;
|
||||
final element =
|
||||
ref.element
|
||||
as $ClassProviderElement<
|
||||
AnyNotifier<core.AudiobookPlayer, core.AudiobookPlayer>,
|
||||
core.AudiobookPlayer,
|
||||
Object?,
|
||||
Object?
|
||||
>;
|
||||
element.handleCreate(ref, build);
|
||||
}
|
||||
}
|
||||
|
||||
@ProviderFor(AudiobookPlayer)
|
||||
final audiobookPlayerProvider = AudiobookPlayerProvider._();
|
||||
|
||||
final class AudiobookPlayerProvider
|
||||
extends $NotifierProvider<AudiobookPlayer, core.AudiobookPlayer> {
|
||||
AudiobookPlayerProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
retry: null,
|
||||
name: r'audiobookPlayerProvider',
|
||||
isAutoDispose: false,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$audiobookPlayerHash();
|
||||
|
||||
@$internal
|
||||
@override
|
||||
AudiobookPlayer create() => AudiobookPlayer();
|
||||
|
||||
/// {@macro riverpod.override_with_value}
|
||||
Override overrideWithValue(core.AudiobookPlayer value) {
|
||||
return $ProviderOverride(
|
||||
origin: this,
|
||||
providerOverride: $SyncValueProvider<core.AudiobookPlayer>(value),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
String _$audiobookPlayerHash() => r'0f180308067486896fec6a65a6afb0e6686ac4a0';
|
||||
|
||||
/// See also [AudiobookPlayer].
|
||||
@ProviderFor(AudiobookPlayer)
|
||||
final audiobookPlayerProvider =
|
||||
NotifierProvider<AudiobookPlayer, core.AudiobookPlayer>.internal(
|
||||
AudiobookPlayer.new,
|
||||
name: r'audiobookPlayerProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$audiobookPlayerHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
typedef _$AudiobookPlayer = Notifier<core.AudiobookPlayer>;
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package
|
||||
abstract class _$AudiobookPlayer extends $Notifier<core.AudiobookPlayer> {
|
||||
core.AudiobookPlayer build();
|
||||
@$mustCallSuper
|
||||
@override
|
||||
void runBuild() {
|
||||
final ref = this.ref as $Ref<core.AudiobookPlayer, core.AudiobookPlayer>;
|
||||
final element =
|
||||
ref.element
|
||||
as $ClassProviderElement<
|
||||
AnyNotifier<core.AudiobookPlayer, core.AudiobookPlayer>,
|
||||
core.AudiobookPlayer,
|
||||
Object?,
|
||||
Object?
|
||||
>;
|
||||
element.handleCreate(ref, build);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,66 +6,147 @@ part of 'currently_playing_provider.dart';
|
|||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
|
||||
@ProviderFor(currentlyPlayingBook)
|
||||
final currentlyPlayingBookProvider = CurrentlyPlayingBookProvider._();
|
||||
|
||||
final class CurrentlyPlayingBookProvider
|
||||
extends $FunctionalProvider<BookExpanded?, BookExpanded?, BookExpanded?>
|
||||
with $Provider<BookExpanded?> {
|
||||
CurrentlyPlayingBookProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
retry: null,
|
||||
name: r'currentlyPlayingBookProvider',
|
||||
isAutoDispose: true,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$currentlyPlayingBookHash();
|
||||
|
||||
@$internal
|
||||
@override
|
||||
$ProviderElement<BookExpanded?> $createElement($ProviderPointer pointer) =>
|
||||
$ProviderElement(pointer);
|
||||
|
||||
@override
|
||||
BookExpanded? create(Ref ref) {
|
||||
return currentlyPlayingBook(ref);
|
||||
}
|
||||
|
||||
/// {@macro riverpod.override_with_value}
|
||||
Override overrideWithValue(BookExpanded? value) {
|
||||
return $ProviderOverride(
|
||||
origin: this,
|
||||
providerOverride: $SyncValueProvider<BookExpanded?>(value),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
String _$currentlyPlayingBookHash() =>
|
||||
r'e4258694c8f0d1e89651b330fae0f672ca13a484';
|
||||
|
||||
/// See also [currentlyPlayingBook].
|
||||
@ProviderFor(currentlyPlayingBook)
|
||||
final currentlyPlayingBookProvider =
|
||||
AutoDisposeProvider<BookExpanded?>.internal(
|
||||
currentlyPlayingBook,
|
||||
name: r'currentlyPlayingBookProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$currentlyPlayingBookHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
/// provided the current chapter of the book being played
|
||||
|
||||
@ProviderFor(currentPlayingChapter)
|
||||
final currentPlayingChapterProvider = CurrentPlayingChapterProvider._();
|
||||
|
||||
/// provided the current chapter of the book being played
|
||||
|
||||
final class CurrentPlayingChapterProvider
|
||||
extends $FunctionalProvider<BookChapter?, BookChapter?, BookChapter?>
|
||||
with $Provider<BookChapter?> {
|
||||
/// provided the current chapter of the book being played
|
||||
CurrentPlayingChapterProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
retry: null,
|
||||
name: r'currentPlayingChapterProvider',
|
||||
isAutoDispose: true,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$currentPlayingChapterHash();
|
||||
|
||||
@$internal
|
||||
@override
|
||||
$ProviderElement<BookChapter?> $createElement($ProviderPointer pointer) =>
|
||||
$ProviderElement(pointer);
|
||||
|
||||
@override
|
||||
BookChapter? create(Ref ref) {
|
||||
return currentPlayingChapter(ref);
|
||||
}
|
||||
|
||||
/// {@macro riverpod.override_with_value}
|
||||
Override overrideWithValue(BookChapter? value) {
|
||||
return $ProviderOverride(
|
||||
origin: this,
|
||||
providerOverride: $SyncValueProvider<BookChapter?>(value),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||
// ignore: unused_element
|
||||
typedef CurrentlyPlayingBookRef = AutoDisposeProviderRef<BookExpanded?>;
|
||||
String _$currentPlayingChapterHash() =>
|
||||
r'73db8b8a9058573bb0c68ec5d5f8aba9306f3d24';
|
||||
|
||||
/// provided the current chapter of the book being played
|
||||
///
|
||||
/// Copied from [currentPlayingChapter].
|
||||
@ProviderFor(currentPlayingChapter)
|
||||
final currentPlayingChapterProvider =
|
||||
AutoDisposeProvider<BookChapter?>.internal(
|
||||
currentPlayingChapter,
|
||||
name: r'currentPlayingChapterProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$currentPlayingChapterHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
/// provides the book metadata of the currently playing book
|
||||
|
||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||
// ignore: unused_element
|
||||
typedef CurrentPlayingChapterRef = AutoDisposeProviderRef<BookChapter?>;
|
||||
String _$currentBookMetadataHash() =>
|
||||
r'f537ef4ef19280bc952de658ecf6520c535ae344';
|
||||
@ProviderFor(currentBookMetadata)
|
||||
final currentBookMetadataProvider = CurrentBookMetadataProvider._();
|
||||
|
||||
/// provides the book metadata of the currently playing book
|
||||
///
|
||||
/// Copied from [currentBookMetadata].
|
||||
@ProviderFor(currentBookMetadata)
|
||||
final currentBookMetadataProvider =
|
||||
AutoDisposeProvider<BookMetadataExpanded?>.internal(
|
||||
currentBookMetadata,
|
||||
name: r'currentBookMetadataProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$currentBookMetadataHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||
// ignore: unused_element
|
||||
typedef CurrentBookMetadataRef = AutoDisposeProviderRef<BookMetadataExpanded?>;
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package
|
||||
final class CurrentBookMetadataProvider
|
||||
extends
|
||||
$FunctionalProvider<
|
||||
BookMetadataExpanded?,
|
||||
BookMetadataExpanded?,
|
||||
BookMetadataExpanded?
|
||||
>
|
||||
with $Provider<BookMetadataExpanded?> {
|
||||
/// provides the book metadata of the currently playing book
|
||||
CurrentBookMetadataProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
retry: null,
|
||||
name: r'currentBookMetadataProvider',
|
||||
isAutoDispose: true,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$currentBookMetadataHash();
|
||||
|
||||
@$internal
|
||||
@override
|
||||
$ProviderElement<BookMetadataExpanded?> $createElement(
|
||||
$ProviderPointer pointer,
|
||||
) => $ProviderElement(pointer);
|
||||
|
||||
@override
|
||||
BookMetadataExpanded? create(Ref ref) {
|
||||
return currentBookMetadata(ref);
|
||||
}
|
||||
|
||||
/// {@macro riverpod.override_with_value}
|
||||
Override overrideWithValue(BookMetadataExpanded? value) {
|
||||
return $ProviderOverride(
|
||||
origin: this,
|
||||
providerOverride: $SyncValueProvider<BookMetadataExpanded?>(value),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
String _$currentBookMetadataHash() =>
|
||||
r'f537ef4ef19280bc952de658ecf6520c535ae344';
|
||||
|
|
|
|||
|
|
@ -26,11 +26,10 @@ extension on Ref {
|
|||
}
|
||||
|
||||
@Riverpod(keepAlive: true)
|
||||
Raw<ValueNotifier<double>> playerExpandProgressNotifier(
|
||||
Ref ref,
|
||||
) {
|
||||
final ValueNotifier<double> playerExpandProgress =
|
||||
ValueNotifier(playerMinHeight);
|
||||
Raw<ValueNotifier<double>> playerExpandProgressNotifier(Ref ref) {
|
||||
final ValueNotifier<double> playerExpandProgress = ValueNotifier(
|
||||
playerMinHeight,
|
||||
);
|
||||
|
||||
return ref.disposeAndListenChangeNotifier(playerExpandProgress);
|
||||
}
|
||||
|
|
@ -46,10 +45,8 @@ Raw<ValueNotifier<double>> playerExpandProgressNotifier(
|
|||
|
||||
// a provider that will listen to the playerExpandProgressNotifier and return the percentage of the player expanded
|
||||
@Riverpod(keepAlive: true)
|
||||
double playerHeight(
|
||||
Ref ref,
|
||||
) {
|
||||
final playerExpandProgress = ref.watch(playerExpandProgressNotifierProvider);
|
||||
double playerHeight(Ref ref) {
|
||||
final playerExpandProgress = ref.watch(playerExpandProgressProvider);
|
||||
|
||||
// on change of the playerExpandProgress invalidate
|
||||
playerExpandProgress.addListener(() {
|
||||
|
|
@ -63,9 +60,7 @@ double playerHeight(
|
|||
final audioBookMiniplayerController = MiniplayerController();
|
||||
|
||||
@Riverpod(keepAlive: true)
|
||||
bool isPlayerActive(
|
||||
Ref ref,
|
||||
) {
|
||||
bool isPlayerActive(Ref ref) {
|
||||
try {
|
||||
final player = ref.watch(audiobookPlayerProvider);
|
||||
if (player.book != null) {
|
||||
|
|
|
|||
|
|
@ -6,58 +6,134 @@ part of 'player_form.dart';
|
|||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
|
||||
@ProviderFor(playerExpandProgressNotifier)
|
||||
final playerExpandProgressProvider = PlayerExpandProgressNotifierProvider._();
|
||||
|
||||
final class PlayerExpandProgressNotifierProvider
|
||||
extends
|
||||
$FunctionalProvider<
|
||||
Raw<ValueNotifier<double>>,
|
||||
Raw<ValueNotifier<double>>,
|
||||
Raw<ValueNotifier<double>>
|
||||
>
|
||||
with $Provider<Raw<ValueNotifier<double>>> {
|
||||
PlayerExpandProgressNotifierProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
retry: null,
|
||||
name: r'playerExpandProgressProvider',
|
||||
isAutoDispose: false,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$playerExpandProgressNotifierHash();
|
||||
|
||||
@$internal
|
||||
@override
|
||||
$ProviderElement<Raw<ValueNotifier<double>>> $createElement(
|
||||
$ProviderPointer pointer,
|
||||
) => $ProviderElement(pointer);
|
||||
|
||||
@override
|
||||
Raw<ValueNotifier<double>> create(Ref ref) {
|
||||
return playerExpandProgressNotifier(ref);
|
||||
}
|
||||
|
||||
/// {@macro riverpod.override_with_value}
|
||||
Override overrideWithValue(Raw<ValueNotifier<double>> value) {
|
||||
return $ProviderOverride(
|
||||
origin: this,
|
||||
providerOverride: $SyncValueProvider<Raw<ValueNotifier<double>>>(value),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
String _$playerExpandProgressNotifierHash() =>
|
||||
r'1ac7172d90a070f96222286edd1a176be197f378';
|
||||
|
||||
/// See also [playerExpandProgressNotifier].
|
||||
@ProviderFor(playerExpandProgressNotifier)
|
||||
final playerExpandProgressNotifierProvider =
|
||||
Provider<Raw<ValueNotifier<double>>>.internal(
|
||||
playerExpandProgressNotifier,
|
||||
name: r'playerExpandProgressNotifierProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$playerExpandProgressNotifierHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||
// ignore: unused_element
|
||||
typedef PlayerExpandProgressNotifierRef
|
||||
= ProviderRef<Raw<ValueNotifier<double>>>;
|
||||
String _$playerHeightHash() => r'3f031eaffdffbb2c6ddf7eb1aba31bf1619260fc';
|
||||
|
||||
/// See also [playerHeight].
|
||||
@ProviderFor(playerHeight)
|
||||
final playerHeightProvider = Provider<double>.internal(
|
||||
playerHeight,
|
||||
name: r'playerHeightProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product') ? null : _$playerHeightHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
final playerHeightProvider = PlayerHeightProvider._();
|
||||
|
||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||
// ignore: unused_element
|
||||
typedef PlayerHeightRef = ProviderRef<double>;
|
||||
String _$isPlayerActiveHash() => r'2c7ca125423126fb5f0ef218d37bc8fe0ca9ec98';
|
||||
final class PlayerHeightProvider
|
||||
extends $FunctionalProvider<double, double, double>
|
||||
with $Provider<double> {
|
||||
PlayerHeightProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
retry: null,
|
||||
name: r'playerHeightProvider',
|
||||
isAutoDispose: false,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$playerHeightHash();
|
||||
|
||||
@$internal
|
||||
@override
|
||||
$ProviderElement<double> $createElement($ProviderPointer pointer) =>
|
||||
$ProviderElement(pointer);
|
||||
|
||||
@override
|
||||
double create(Ref ref) {
|
||||
return playerHeight(ref);
|
||||
}
|
||||
|
||||
/// {@macro riverpod.override_with_value}
|
||||
Override overrideWithValue(double value) {
|
||||
return $ProviderOverride(
|
||||
origin: this,
|
||||
providerOverride: $SyncValueProvider<double>(value),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
String _$playerHeightHash() => r'41144a733b5ffd1c872a237ed7c9ea5f450dd0d4';
|
||||
|
||||
/// See also [isPlayerActive].
|
||||
@ProviderFor(isPlayerActive)
|
||||
final isPlayerActiveProvider = Provider<bool>.internal(
|
||||
isPlayerActive,
|
||||
name: r'isPlayerActiveProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$isPlayerActiveHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
final isPlayerActiveProvider = IsPlayerActiveProvider._();
|
||||
|
||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||
// ignore: unused_element
|
||||
typedef IsPlayerActiveRef = ProviderRef<bool>;
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package
|
||||
final class IsPlayerActiveProvider extends $FunctionalProvider<bool, bool, bool>
|
||||
with $Provider<bool> {
|
||||
IsPlayerActiveProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
retry: null,
|
||||
name: r'isPlayerActiveProvider',
|
||||
isAutoDispose: false,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$isPlayerActiveHash();
|
||||
|
||||
@$internal
|
||||
@override
|
||||
$ProviderElement<bool> $createElement($ProviderPointer pointer) =>
|
||||
$ProviderElement(pointer);
|
||||
|
||||
@override
|
||||
bool create(Ref ref) {
|
||||
return isPlayerActive(ref);
|
||||
}
|
||||
|
||||
/// {@macro riverpod.override_with_value}
|
||||
Override overrideWithValue(bool value) {
|
||||
return $ProviderOverride(
|
||||
origin: this,
|
||||
providerOverride: $SyncValueProvider<bool>(value),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
String _$isPlayerActiveHash() => r'2c7ca125423126fb5f0ef218d37bc8fe0ca9ec98';
|
||||
|
|
|
|||
|
|
@ -31,19 +31,15 @@ class AudiobookPlayer extends HookConsumerWidget {
|
|||
if (currentBook == null) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
final itemBeingPlayed =
|
||||
ref.watch(libraryItemProvider(currentBook.libraryItemId));
|
||||
final itemBeingPlayed = ref.watch(
|
||||
libraryItemProvider(currentBook.libraryItemId),
|
||||
);
|
||||
final player = ref.watch(audiobookPlayerProvider);
|
||||
final imageOfItemBeingPlayed = itemBeingPlayed.valueOrNull != null
|
||||
? ref.watch(
|
||||
coverImageProvider(itemBeingPlayed.valueOrNull!.id),
|
||||
)
|
||||
final imageOfItemBeingPlayed = itemBeingPlayed.value != null
|
||||
? ref.watch(coverImageProvider(itemBeingPlayed.value!.id))
|
||||
: null;
|
||||
final imgWidget = imageOfItemBeingPlayed?.valueOrNull != null
|
||||
? Image.memory(
|
||||
imageOfItemBeingPlayed!.valueOrNull!,
|
||||
fit: BoxFit.cover,
|
||||
)
|
||||
final imgWidget = imageOfItemBeingPlayed?.value != null
|
||||
? Image.memory(imageOfItemBeingPlayed!.value!, fit: BoxFit.cover)
|
||||
: const BookCoverSkeleton();
|
||||
|
||||
final playPauseController = useAnimationController(
|
||||
|
|
@ -63,9 +59,10 @@ class AudiobookPlayer extends HookConsumerWidget {
|
|||
// theme from image
|
||||
final imageTheme = ref.watch(
|
||||
themeOfLibraryItemProvider(
|
||||
itemBeingPlayed.valueOrNull?.id,
|
||||
itemBeingPlayed.value?.id,
|
||||
brightness: Theme.of(context).brightness,
|
||||
highContrast: appSettings.themeSettings.highContrast ||
|
||||
highContrast:
|
||||
appSettings.themeSettings.highContrast ||
|
||||
MediaQuery.of(context).highContrast,
|
||||
),
|
||||
);
|
||||
|
|
@ -81,15 +78,16 @@ class AudiobookPlayer extends HookConsumerWidget {
|
|||
final preferredVolume = appSettings.playerSettings.preferredDefaultVolume;
|
||||
return Theme(
|
||||
data: ThemeData(
|
||||
colorScheme: imageTheme.valueOrNull ?? Theme.of(context).colorScheme,
|
||||
colorScheme: imageTheme.value ?? Theme.of(context).colorScheme,
|
||||
),
|
||||
child: Miniplayer(
|
||||
valueNotifier: ref.watch(playerExpandProgressNotifierProvider),
|
||||
valueNotifier: ref.watch(playerExpandProgressProvider),
|
||||
onDragDown: (percentage) async {
|
||||
// preferred volume
|
||||
// set volume to 0 when dragging down
|
||||
await player
|
||||
.setVolume(preferredVolume * (1 - percentage.clamp(0, .75)));
|
||||
await player.setVolume(
|
||||
preferredVolume * (1 - percentage.clamp(0, .75)),
|
||||
);
|
||||
},
|
||||
minHeight: playerMinHeight,
|
||||
// subtract the height of notches and other system UI
|
||||
|
|
@ -109,17 +107,14 @@ class AudiobookPlayer extends HookConsumerWidget {
|
|||
// also at this point the image should be at its max size and in the center of the player
|
||||
final miniplayerPercentageDeclaration =
|
||||
(maxImgSize - playerMinHeight) /
|
||||
(playerMaxHeight - playerMinHeight);
|
||||
(playerMaxHeight - playerMinHeight);
|
||||
final bool isFormMiniplayer =
|
||||
percentage < miniplayerPercentageDeclaration;
|
||||
|
||||
if (!isFormMiniplayer) {
|
||||
// this calculation needs a refactor
|
||||
var percentageExpandedPlayer = percentage
|
||||
.inverseLerp(
|
||||
miniplayerPercentageDeclaration,
|
||||
1,
|
||||
)
|
||||
.inverseLerp(miniplayerPercentageDeclaration, 1)
|
||||
.clamp(0.0, 1.0);
|
||||
|
||||
return PlayerWhenExpanded(
|
||||
|
|
@ -164,37 +159,33 @@ class AudiobookPlayerPlayPauseButton extends HookConsumerWidget {
|
|||
|
||||
return switch (player.processingState) {
|
||||
ProcessingState.loading || ProcessingState.buffering => const Padding(
|
||||
padding: EdgeInsets.all(8.0),
|
||||
child: CircularProgressIndicator(),
|
||||
),
|
||||
padding: EdgeInsets.all(8.0),
|
||||
child: CircularProgressIndicator(),
|
||||
),
|
||||
ProcessingState.completed => IconButton(
|
||||
onPressed: () async {
|
||||
await player.seek(const Duration(seconds: 0));
|
||||
await player.play();
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons.replay,
|
||||
),
|
||||
),
|
||||
onPressed: () async {
|
||||
await player.seek(const Duration(seconds: 0));
|
||||
await player.play();
|
||||
},
|
||||
icon: const Icon(Icons.replay),
|
||||
),
|
||||
ProcessingState.ready => IconButton(
|
||||
onPressed: () async {
|
||||
await player.togglePlayPause();
|
||||
},
|
||||
iconSize: iconSize,
|
||||
icon: AnimatedIcon(
|
||||
icon: AnimatedIcons.play_pause,
|
||||
progress: playPauseController,
|
||||
),
|
||||
onPressed: () async {
|
||||
await player.togglePlayPause();
|
||||
},
|
||||
iconSize: iconSize,
|
||||
icon: AnimatedIcon(
|
||||
icon: AnimatedIcons.play_pause,
|
||||
progress: playPauseController,
|
||||
),
|
||||
),
|
||||
ProcessingState.idle => const SizedBox.shrink(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
class AudiobookChapterProgressBar extends HookConsumerWidget {
|
||||
const AudiobookChapterProgressBar({
|
||||
super.key,
|
||||
});
|
||||
const AudiobookChapterProgressBar({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
|
|
|
|||
|
|
@ -38,10 +38,7 @@ class PlayerWhenExpanded extends HookConsumerWidget {
|
|||
const lateStart = 0.4;
|
||||
const earlyEnd = 1;
|
||||
final earlyPercentage = percentageExpandedPlayer
|
||||
.inverseLerp(
|
||||
lateStart,
|
||||
earlyEnd,
|
||||
)
|
||||
.inverseLerp(lateStart, earlyEnd)
|
||||
.clamp(0.0, 1.0);
|
||||
final currentChapter = ref.watch(currentPlayingChapterProvider);
|
||||
final currentBookMetadata = ref.watch(currentBookMetadataProvider);
|
||||
|
|
@ -49,15 +46,11 @@ class PlayerWhenExpanded extends HookConsumerWidget {
|
|||
return Column(
|
||||
children: [
|
||||
// sized box for system status bar; not needed as not full screen
|
||||
SizedBox(
|
||||
height: MediaQuery.of(context).padding.top * earlyPercentage,
|
||||
),
|
||||
SizedBox(height: MediaQuery.of(context).padding.top * earlyPercentage),
|
||||
|
||||
// a row with a down arrow to minimize the player, a pill shaped container to drag the player, and a cast button
|
||||
ConstrainedBox(
|
||||
constraints: BoxConstraints(
|
||||
maxHeight: 100 * earlyPercentage,
|
||||
),
|
||||
constraints: BoxConstraints(maxHeight: 100 * earlyPercentage),
|
||||
child: Opacity(
|
||||
opacity: earlyPercentage,
|
||||
child: Padding(
|
||||
|
|
@ -104,10 +97,9 @@ class PlayerWhenExpanded extends HookConsumerWidget {
|
|||
decoration: BoxDecoration(
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.primary
|
||||
.withValues(alpha: 0.1),
|
||||
color: Theme.of(
|
||||
context,
|
||||
).colorScheme.primary.withValues(alpha: 0.1),
|
||||
blurRadius: 32 * earlyPercentage,
|
||||
spreadRadius: 8 * earlyPercentage,
|
||||
// offset: Offset(0, 16 * earlyPercentage),
|
||||
|
|
@ -170,11 +162,10 @@ class PlayerWhenExpanded extends HookConsumerWidget {
|
|||
currentBookMetadata?.authorName ?? '',
|
||||
].join(' - '),
|
||||
style: Theme.of(context).textTheme.titleMedium?.copyWith(
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.onSurface
|
||||
.withValues(alpha: 0.7),
|
||||
),
|
||||
color: Theme.of(
|
||||
context,
|
||||
).colorScheme.onSurface.withValues(alpha: 0.7),
|
||||
),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
|
|
|
|||
|
|
@ -32,8 +32,10 @@ class PlayerWhenMinimized extends HookConsumerWidget {
|
|||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final player = ref.watch(audiobookPlayerProvider);
|
||||
final vanishingPercentage = 1 - percentageMiniplayer;
|
||||
final progress =
|
||||
useStream(player.slowPositionStream, initialData: Duration.zero);
|
||||
final progress = useStream(
|
||||
player.slowPositionStream,
|
||||
initialData: Duration.zero,
|
||||
);
|
||||
|
||||
final bookMetaExpanded = ref.watch(currentBookMetadataProvider);
|
||||
|
||||
|
|
@ -61,9 +63,7 @@ class PlayerWhenMinimized extends HookConsumerWidget {
|
|||
);
|
||||
},
|
||||
child: ConstrainedBox(
|
||||
constraints: BoxConstraints(
|
||||
maxWidth: maxImgSize,
|
||||
),
|
||||
constraints: BoxConstraints(maxWidth: maxImgSize),
|
||||
child: imgWidget,
|
||||
),
|
||||
),
|
||||
|
|
@ -80,7 +80,8 @@ class PlayerWhenMinimized extends HookConsumerWidget {
|
|||
// AutoScrollText(
|
||||
Text(
|
||||
bookMetaExpanded?.title ?? '',
|
||||
maxLines: 1, overflow: TextOverflow.ellipsis,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
// velocity:
|
||||
// const Velocity(pixelsPerSecond: Offset(16, 0)),
|
||||
style: Theme.of(context).textTheme.bodyLarge,
|
||||
|
|
@ -90,11 +91,10 @@ class PlayerWhenMinimized extends HookConsumerWidget {
|
|||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.onSurface
|
||||
.withValues(alpha: 0.7),
|
||||
),
|
||||
color: Theme.of(
|
||||
context,
|
||||
).colorScheme.onSurface.withValues(alpha: 0.7),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
|
@ -135,7 +135,8 @@ class PlayerWhenMinimized extends HookConsumerWidget {
|
|||
SizedBox(
|
||||
height: barHeight,
|
||||
child: LinearProgressIndicator(
|
||||
value: (progress.data ?? Duration.zero).inSeconds /
|
||||
value:
|
||||
(progress.data ?? Duration.zero).inSeconds /
|
||||
player.book!.duration.inSeconds,
|
||||
color: Theme.of(context).colorScheme.onPrimaryContainer,
|
||||
backgroundColor: Theme.of(context).colorScheme.primaryContainer,
|
||||
|
|
|
|||
|
|
@ -4,10 +4,7 @@ import 'package:vaani/constants/sizes.dart';
|
|||
import 'package:vaani/features/player/providers/audiobook_player.dart';
|
||||
|
||||
class AudiobookPlayerSeekButton extends HookConsumerWidget {
|
||||
const AudiobookPlayerSeekButton({
|
||||
super.key,
|
||||
required this.isForward,
|
||||
});
|
||||
const AudiobookPlayerSeekButton({super.key, required this.isForward});
|
||||
|
||||
/// if true, the button seeks forward, else it seeks backwards
|
||||
final bool isForward;
|
||||
|
|
|
|||
|
|
@ -5,10 +5,7 @@ import 'package:vaani/constants/sizes.dart';
|
|||
import 'package:vaani/features/player/providers/audiobook_player.dart';
|
||||
|
||||
class AudiobookPlayerSeekChapterButton extends HookConsumerWidget {
|
||||
const AudiobookPlayerSeekChapterButton({
|
||||
super.key,
|
||||
required this.isForward,
|
||||
});
|
||||
const AudiobookPlayerSeekChapterButton({super.key, required this.isForward});
|
||||
|
||||
/// if true, the button seeks forward, else it seeks backwards
|
||||
final bool isForward;
|
||||
|
|
@ -27,9 +24,7 @@ class AudiobookPlayerSeekChapterButton extends HookConsumerWidget {
|
|||
void seekForward() {
|
||||
final index = player.book!.chapters.indexOf(player.currentChapter!);
|
||||
if (index < player.book!.chapters.length - 1) {
|
||||
player.seek(
|
||||
player.book!.chapters[index + 1].start + offset,
|
||||
);
|
||||
player.seek(player.book!.chapters[index + 1].start + offset);
|
||||
} else {
|
||||
player.seek(player.currentChapter!.end);
|
||||
}
|
||||
|
|
@ -37,8 +32,9 @@ class AudiobookPlayerSeekChapterButton extends HookConsumerWidget {
|
|||
|
||||
/// seek backward to the previous chapter or the start of the current chapter
|
||||
void seekBackward() {
|
||||
final currentPlayingChapterIndex =
|
||||
player.book!.chapters.indexOf(player.currentChapter!);
|
||||
final currentPlayingChapterIndex = player.book!.chapters.indexOf(
|
||||
player.currentChapter!,
|
||||
);
|
||||
final chapterPosition =
|
||||
player.positionInBook - player.currentChapter!.start;
|
||||
BookChapter chapterToSeekTo;
|
||||
|
|
@ -49,9 +45,7 @@ class AudiobookPlayerSeekChapterButton extends HookConsumerWidget {
|
|||
} else {
|
||||
chapterToSeekTo = player.currentChapter!;
|
||||
}
|
||||
player.seek(
|
||||
chapterToSeekTo.start + offset,
|
||||
);
|
||||
player.seek(chapterToSeekTo.start + offset);
|
||||
}
|
||||
|
||||
return IconButton(
|
||||
|
|
|
|||
|
|
@ -15,9 +15,7 @@ import 'package:vaani/shared/extensions/duration_format.dart'
|
|||
import 'package:vaani/shared/hooks.dart' show useTimer;
|
||||
|
||||
class ChapterSelectionButton extends HookConsumerWidget {
|
||||
const ChapterSelectionButton({
|
||||
super.key,
|
||||
});
|
||||
const ChapterSelectionButton({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
|
|
@ -49,9 +47,7 @@ class ChapterSelectionButton extends HookConsumerWidget {
|
|||
}
|
||||
|
||||
class ChapterSelectionModal extends HookConsumerWidget {
|
||||
const ChapterSelectionModal({
|
||||
super.key,
|
||||
});
|
||||
const ChapterSelectionModal({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
|
|
@ -87,41 +83,40 @@ class ChapterSelectionModal extends HookConsumerWidget {
|
|||
child: currentBook?.chapters == null
|
||||
? const Text('No chapters found')
|
||||
: Column(
|
||||
children: currentBook!.chapters.map(
|
||||
(chapter) {
|
||||
final isCurrent = currentChapterIndex == chapter.id;
|
||||
final isPlayed = currentChapterIndex != null &&
|
||||
chapter.id < currentChapterIndex;
|
||||
return ListTile(
|
||||
autofocus: isCurrent,
|
||||
iconColor: isPlayed && !isCurrent
|
||||
? theme.disabledColor
|
||||
children: currentBook!.chapters.map((chapter) {
|
||||
final isCurrent = currentChapterIndex == chapter.id;
|
||||
final isPlayed =
|
||||
currentChapterIndex != null &&
|
||||
chapter.id < currentChapterIndex;
|
||||
return ListTile(
|
||||
autofocus: isCurrent,
|
||||
iconColor: isPlayed && !isCurrent
|
||||
? theme.disabledColor
|
||||
: null,
|
||||
title: Text(
|
||||
chapter.title,
|
||||
style: isPlayed && !isCurrent
|
||||
? TextStyle(color: theme.disabledColor)
|
||||
: null,
|
||||
title: Text(
|
||||
chapter.title,
|
||||
style: isPlayed && !isCurrent
|
||||
? TextStyle(color: theme.disabledColor)
|
||||
: null,
|
||||
),
|
||||
subtitle: Text(
|
||||
'(${chapter.duration.smartBinaryFormat})',
|
||||
style: isPlayed && !isCurrent
|
||||
? TextStyle(color: theme.disabledColor)
|
||||
: null,
|
||||
),
|
||||
trailing: isCurrent
|
||||
? const PlayingIndicatorIcon()
|
||||
: const Icon(Icons.play_arrow),
|
||||
selected: isCurrent,
|
||||
key: isCurrent ? chapterKey : null,
|
||||
onTap: () {
|
||||
Navigator.of(context).pop();
|
||||
notifier.seek(chapter.start + 90.ms);
|
||||
notifier.play();
|
||||
},
|
||||
);
|
||||
},
|
||||
).toList(),
|
||||
),
|
||||
subtitle: Text(
|
||||
'(${chapter.duration.smartBinaryFormat})',
|
||||
style: isPlayed && !isCurrent
|
||||
? TextStyle(color: theme.disabledColor)
|
||||
: null,
|
||||
),
|
||||
trailing: isCurrent
|
||||
? const PlayingIndicatorIcon()
|
||||
: const Icon(Icons.play_arrow),
|
||||
selected: isCurrent,
|
||||
key: isCurrent ? chapterKey : null,
|
||||
onTap: () {
|
||||
Navigator.of(context).pop();
|
||||
notifier.seek(chapter.start + 90.ms);
|
||||
notifier.play();
|
||||
},
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -10,9 +10,7 @@ import 'package:vaani/settings/app_settings_provider.dart';
|
|||
final _logger = Logger('PlayerSpeedAdjustButton');
|
||||
|
||||
class PlayerSpeedAdjustButton extends HookConsumerWidget {
|
||||
const PlayerSpeedAdjustButton({
|
||||
super.key,
|
||||
});
|
||||
const PlayerSpeedAdjustButton({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
|
|
@ -35,21 +33,19 @@ class PlayerSpeedAdjustButton extends HookConsumerWidget {
|
|||
notifier.setSpeed(speed);
|
||||
if (appSettings.playerSettings.configurePlayerForEveryBook) {
|
||||
ref
|
||||
.read(
|
||||
bookSettingsProvider(bookId).notifier,
|
||||
)
|
||||
.read(bookSettingsProvider(bookId).notifier)
|
||||
.update(
|
||||
bookSettings.copyWith
|
||||
.playerSettings(preferredDefaultSpeed: speed),
|
||||
bookSettings.copyWith.playerSettings(
|
||||
preferredDefaultSpeed: speed,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
ref
|
||||
.read(
|
||||
appSettingsProvider.notifier,
|
||||
)
|
||||
.read(appSettingsProvider.notifier)
|
||||
.update(
|
||||
appSettings.copyWith
|
||||
.playerSettings(preferredDefaultSpeed: speed),
|
||||
appSettings.copyWith.playerSettings(
|
||||
preferredDefaultSpeed: speed,
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -59,8 +59,11 @@ class _PlayingIndicatorIconState extends State<PlayingIndicatorIcon> {
|
|||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_animationParams =
|
||||
List.generate(widget.barCount, _createRandomParams, growable: false);
|
||||
_animationParams = List.generate(
|
||||
widget.barCount,
|
||||
_createRandomParams,
|
||||
growable: false,
|
||||
);
|
||||
}
|
||||
|
||||
// Helper to generate random parameters for one bar's animation cycle
|
||||
|
|
@ -72,10 +75,12 @@ class _PlayingIndicatorIconState extends State<PlayingIndicatorIcon> {
|
|||
|
||||
// Note: These factors represent the scale relative to the *half-height*
|
||||
// if centerSymmetric is true, controlled by the alignment in scaleY.
|
||||
final targetHeightFactor1 = widget.minHeightFactor +
|
||||
final targetHeightFactor1 =
|
||||
widget.minHeightFactor +
|
||||
_random.nextDouble() *
|
||||
(widget.maxHeightFactor - widget.minHeightFactor);
|
||||
final targetHeightFactor2 = widget.minHeightFactor +
|
||||
final targetHeightFactor2 =
|
||||
widget.minHeightFactor +
|
||||
_random.nextDouble() *
|
||||
(widget.maxHeightFactor - widget.minHeightFactor);
|
||||
|
||||
|
|
@ -95,7 +100,8 @@ class _PlayingIndicatorIconState extends State<PlayingIndicatorIcon> {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final color = widget.color ??
|
||||
final color =
|
||||
widget.color ??
|
||||
IconTheme.of(context).color ??
|
||||
Theme.of(context).colorScheme.primary;
|
||||
|
||||
|
|
@ -110,8 +116,9 @@ class _PlayingIndicatorIconState extends State<PlayingIndicatorIcon> {
|
|||
final double maxHeight = widget.size;
|
||||
|
||||
// Determine the alignment for scaling based on the symmetric flag
|
||||
final Alignment scaleAlignment =
|
||||
widget.centerSymmetric ? Alignment.center : Alignment.bottomCenter;
|
||||
final Alignment scaleAlignment = widget.centerSymmetric
|
||||
? Alignment.center
|
||||
: Alignment.bottomCenter;
|
||||
|
||||
// Determine the cross axis alignment for the Row
|
||||
final CrossAxisAlignment rowAlignment = widget.centerSymmetric
|
||||
|
|
@ -129,47 +136,40 @@ class _PlayingIndicatorIconState extends State<PlayingIndicatorIcon> {
|
|||
crossAxisAlignment: rowAlignment,
|
||||
// Use spaceEvenly for better distribution, especially with center alignment
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: List.generate(
|
||||
widget.barCount,
|
||||
(index) {
|
||||
final params = _animationParams[index];
|
||||
// The actual bar widget that will be animated
|
||||
return Container(
|
||||
width: barWidth,
|
||||
// Set initial height to the max potential height
|
||||
// The scaleY animation will control the visible height
|
||||
height: maxHeight,
|
||||
decoration: BoxDecoration(
|
||||
color: color,
|
||||
borderRadius: BorderRadius.circular(barWidth / 2),
|
||||
),
|
||||
)
|
||||
.animate(
|
||||
delay: params.initialDelay,
|
||||
onPlay: (controller) => controller.repeat(
|
||||
reverse: true,
|
||||
),
|
||||
)
|
||||
// 1. Scale to targetHeightFactor1
|
||||
.scaleY(
|
||||
begin:
|
||||
widget.minHeightFactor, // Scale factor starts near min
|
||||
end: params.targetHeightFactor1,
|
||||
duration: params.duration1,
|
||||
curve: Curves.easeInOutCirc,
|
||||
alignment: scaleAlignment, // Apply chosen alignment
|
||||
)
|
||||
// 2. Then scale to targetHeightFactor2
|
||||
.then()
|
||||
.scaleY(
|
||||
end: params.targetHeightFactor2,
|
||||
duration: params.duration2,
|
||||
curve: Curves.easeInOutCirc,
|
||||
alignment: scaleAlignment, // Apply chosen alignment
|
||||
);
|
||||
},
|
||||
growable: false,
|
||||
),
|
||||
children: List.generate(widget.barCount, (index) {
|
||||
final params = _animationParams[index];
|
||||
// The actual bar widget that will be animated
|
||||
return Container(
|
||||
width: barWidth,
|
||||
// Set initial height to the max potential height
|
||||
// The scaleY animation will control the visible height
|
||||
height: maxHeight,
|
||||
decoration: BoxDecoration(
|
||||
color: color,
|
||||
borderRadius: BorderRadius.circular(barWidth / 2),
|
||||
),
|
||||
)
|
||||
.animate(
|
||||
delay: params.initialDelay,
|
||||
onPlay: (controller) => controller.repeat(reverse: true),
|
||||
)
|
||||
// 1. Scale to targetHeightFactor1
|
||||
.scaleY(
|
||||
begin: widget.minHeightFactor, // Scale factor starts near min
|
||||
end: params.targetHeightFactor1,
|
||||
duration: params.duration1,
|
||||
curve: Curves.easeInOutCirc,
|
||||
alignment: scaleAlignment, // Apply chosen alignment
|
||||
)
|
||||
// 2. Then scale to targetHeightFactor2
|
||||
.then()
|
||||
.scaleY(
|
||||
end: params.targetHeightFactor2,
|
||||
duration: params.duration2,
|
||||
curve: Curves.easeInOutCirc,
|
||||
alignment: scaleAlignment, // Apply chosen alignment
|
||||
);
|
||||
}, growable: false),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -10,10 +10,7 @@ import 'package:vaani/settings/app_settings_provider.dart';
|
|||
const double itemExtent = 25;
|
||||
|
||||
class SpeedSelector extends HookConsumerWidget {
|
||||
const SpeedSelector({
|
||||
super.key,
|
||||
required this.onSpeedSelected,
|
||||
});
|
||||
const SpeedSelector({super.key, required this.onSpeedSelected});
|
||||
|
||||
final void Function(double speed) onSpeedSelected;
|
||||
|
||||
|
|
@ -26,34 +23,22 @@ class SpeedSelector extends HookConsumerWidget {
|
|||
final speedState = useState(currentSpeed);
|
||||
|
||||
// hook the onSpeedSelected function to the state
|
||||
useEffect(
|
||||
() {
|
||||
onSpeedSelected(speedState.value);
|
||||
return null;
|
||||
},
|
||||
[speedState.value],
|
||||
);
|
||||
useEffect(() {
|
||||
onSpeedSelected(speedState.value);
|
||||
return null;
|
||||
}, [speedState.value]);
|
||||
|
||||
// the speed options
|
||||
final minSpeed = min(
|
||||
speeds.reduce(min),
|
||||
playerSettings.minSpeed,
|
||||
);
|
||||
final maxSpeed = max(
|
||||
speeds.reduce(max),
|
||||
playerSettings.maxSpeed,
|
||||
);
|
||||
final minSpeed = min(speeds.reduce(min), playerSettings.minSpeed);
|
||||
final maxSpeed = max(speeds.reduce(max), playerSettings.maxSpeed);
|
||||
final speedIncrement = playerSettings.speedIncrement;
|
||||
final availableSpeeds = ((maxSpeed - minSpeed) / speedIncrement).ceil() + 1;
|
||||
final availableSpeedsList = List.generate(
|
||||
availableSpeeds,
|
||||
(index) {
|
||||
// need to round to 2 decimal place to avoid floating point errors
|
||||
return double.parse(
|
||||
(minSpeed + index * speedIncrement).toStringAsFixed(2),
|
||||
);
|
||||
},
|
||||
);
|
||||
final availableSpeedsList = List.generate(availableSpeeds, (index) {
|
||||
// need to round to 2 decimal place to avoid floating point errors
|
||||
return double.parse(
|
||||
(minSpeed + index * speedIncrement).toStringAsFixed(2),
|
||||
);
|
||||
});
|
||||
|
||||
final scrollController = useFixedExtentScrollController(
|
||||
initialItem: availableSpeedsList.indexOf(currentSpeed),
|
||||
|
|
@ -107,18 +92,19 @@ class SpeedSelector extends HookConsumerWidget {
|
|||
(speed) => TextButton(
|
||||
style: speed == speedState.value
|
||||
? TextButton.styleFrom(
|
||||
backgroundColor:
|
||||
Theme.of(context).colorScheme.primaryContainer,
|
||||
foregroundColor: Theme.of(context)
|
||||
.colorScheme
|
||||
.onPrimaryContainer,
|
||||
backgroundColor: Theme.of(
|
||||
context,
|
||||
).colorScheme.primaryContainer,
|
||||
foregroundColor: Theme.of(
|
||||
context,
|
||||
).colorScheme.onPrimaryContainer,
|
||||
)
|
||||
// border if not selected
|
||||
: TextButton.styleFrom(
|
||||
side: BorderSide(
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.primaryContainer,
|
||||
color: Theme.of(
|
||||
context,
|
||||
).colorScheme.primaryContainer,
|
||||
),
|
||||
),
|
||||
onPressed: () async {
|
||||
|
|
@ -195,14 +181,13 @@ class SpeedWheel extends StatelessWidget {
|
|||
controller: scrollController,
|
||||
scrollDirection: Axis.horizontal,
|
||||
itemExtent: itemExtent,
|
||||
diameterRatio: 1.5, squeeze: 1.2,
|
||||
diameterRatio: 1.5,
|
||||
squeeze: 1.2,
|
||||
// useMagnifier: true,
|
||||
// magnification: 1.5,
|
||||
physics: const FixedExtentScrollPhysics(),
|
||||
children: availableSpeedsList
|
||||
.map(
|
||||
(speed) => SpeedLine(speed: speed),
|
||||
)
|
||||
.map((speed) => SpeedLine(speed: speed))
|
||||
.toList(),
|
||||
onSelectedItemChanged: (index) {
|
||||
speedState.value = availableSpeedsList[index];
|
||||
|
|
@ -232,10 +217,7 @@ class SpeedWheel extends StatelessWidget {
|
|||
}
|
||||
|
||||
class SpeedLine extends StatelessWidget {
|
||||
const SpeedLine({
|
||||
super.key,
|
||||
required this.speed,
|
||||
});
|
||||
const SpeedLine({super.key, required this.speed});
|
||||
|
||||
final double speed;
|
||||
|
||||
|
|
@ -250,8 +232,8 @@ class SpeedLine extends StatelessWidget {
|
|||
width: speed % 0.5 == 0
|
||||
? 3
|
||||
: speed % 0.25 == 0
|
||||
? 2
|
||||
: 0.5,
|
||||
? 2
|
||||
: 0.5,
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ class ShakeDetector {
|
|||
DateTime _lastShakeTime = DateTime.now();
|
||||
|
||||
final StreamController<UserAccelerometerEvent>
|
||||
_detectedShakeStreamController = StreamController.broadcast();
|
||||
_detectedShakeStreamController = StreamController.broadcast();
|
||||
|
||||
void start() {
|
||||
if (_accelerometerSubscription != null) {
|
||||
|
|
@ -37,26 +37,27 @@ class ShakeDetector {
|
|||
return;
|
||||
}
|
||||
_accelerometerSubscription =
|
||||
userAccelerometerEventStream(samplingPeriod: _settings.samplingPeriod)
|
||||
.listen((event) {
|
||||
_logger.finest('RMS: ${event.rms}');
|
||||
if (event.rms > _settings.threshold) {
|
||||
_currentShakeCount++;
|
||||
userAccelerometerEventStream(
|
||||
samplingPeriod: _settings.samplingPeriod,
|
||||
).listen((event) {
|
||||
_logger.finest('RMS: ${event.rms}');
|
||||
if (event.rms > _settings.threshold) {
|
||||
_currentShakeCount++;
|
||||
|
||||
if (_currentShakeCount >= _settings.shakeTriggerCount &&
|
||||
!isCoolDownNeeded()) {
|
||||
_logger.fine('Shake detected $_currentShakeCount times');
|
||||
if (_currentShakeCount >= _settings.shakeTriggerCount &&
|
||||
!isCoolDownNeeded()) {
|
||||
_logger.fine('Shake detected $_currentShakeCount times');
|
||||
|
||||
onShakeDetected?.call();
|
||||
_detectedShakeStreamController.add(event);
|
||||
onShakeDetected?.call();
|
||||
_detectedShakeStreamController.add(event);
|
||||
|
||||
_lastShakeTime = DateTime.now();
|
||||
_currentShakeCount = 0;
|
||||
}
|
||||
} else {
|
||||
_currentShakeCount = 0;
|
||||
}
|
||||
});
|
||||
_lastShakeTime = DateTime.now();
|
||||
_currentShakeCount = 0;
|
||||
}
|
||||
} else {
|
||||
_currentShakeCount = 0;
|
||||
}
|
||||
});
|
||||
|
||||
_logger.fine('ShakeDetector started');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,34 +59,29 @@ class ShakeDetector extends _$ShakeDetector {
|
|||
final sleepTimer = ref.watch(sleepTimerProvider);
|
||||
if (!shakeDetectionSettings.shakeAction.isPlaybackManagementEnabled &&
|
||||
sleepTimer == null) {
|
||||
_logger
|
||||
.config('No playback management is enabled and sleep timer is off, '
|
||||
'so shake detection is disabled');
|
||||
_logger.config(
|
||||
'No playback management is enabled and sleep timer is off, '
|
||||
'so shake detection is disabled',
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
_logger.config('Creating shake detector');
|
||||
final detector = core.ShakeDetector(
|
||||
shakeDetectionSettings,
|
||||
() {
|
||||
final wasActionComplete = doShakeAction(
|
||||
shakeDetectionSettings.shakeAction,
|
||||
ref: ref,
|
||||
);
|
||||
if (wasActionComplete) {
|
||||
shakeDetectionSettings.feedback.forEach(postShakeFeedback);
|
||||
}
|
||||
},
|
||||
);
|
||||
final detector = core.ShakeDetector(shakeDetectionSettings, () {
|
||||
final wasActionComplete = doShakeAction(
|
||||
shakeDetectionSettings.shakeAction,
|
||||
ref: ref,
|
||||
);
|
||||
if (wasActionComplete) {
|
||||
shakeDetectionSettings.feedback.forEach(postShakeFeedback);
|
||||
}
|
||||
});
|
||||
ref.onDispose(detector.dispose);
|
||||
return detector;
|
||||
}
|
||||
|
||||
/// Perform the shake action and return whether the action was successful
|
||||
bool doShakeAction(
|
||||
ShakeAction shakeAction, {
|
||||
required Ref ref,
|
||||
}) {
|
||||
bool doShakeAction(ShakeAction shakeAction, {required Ref ref}) {
|
||||
final player = ref.read(simpleAudiobookPlayerProvider);
|
||||
if (player.book == null && shakeAction.isPlaybackManagementEnabled) {
|
||||
_logger.warning('No book is loaded');
|
||||
|
|
@ -166,8 +161,11 @@ extension on ShakeAction {
|
|||
}
|
||||
|
||||
bool get isPlaybackManagementEnabled {
|
||||
return {ShakeAction.playPause, ShakeAction.fastForward, ShakeAction.rewind}
|
||||
.contains(this);
|
||||
return {
|
||||
ShakeAction.playPause,
|
||||
ShakeAction.fastForward,
|
||||
ShakeAction.rewind,
|
||||
}.contains(this);
|
||||
}
|
||||
|
||||
bool get shouldActOnSleepTimer {
|
||||
|
|
|
|||
|
|
@ -6,21 +6,57 @@ part of 'shake_detector.dart';
|
|||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
|
||||
@ProviderFor(ShakeDetector)
|
||||
final shakeDetectorProvider = ShakeDetectorProvider._();
|
||||
|
||||
final class ShakeDetectorProvider
|
||||
extends $NotifierProvider<ShakeDetector, core.ShakeDetector?> {
|
||||
ShakeDetectorProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
retry: null,
|
||||
name: r'shakeDetectorProvider',
|
||||
isAutoDispose: true,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$shakeDetectorHash();
|
||||
|
||||
@$internal
|
||||
@override
|
||||
ShakeDetector create() => ShakeDetector();
|
||||
|
||||
/// {@macro riverpod.override_with_value}
|
||||
Override overrideWithValue(core.ShakeDetector? value) {
|
||||
return $ProviderOverride(
|
||||
origin: this,
|
||||
providerOverride: $SyncValueProvider<core.ShakeDetector?>(value),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
String _$shakeDetectorHash() => r'2a380bab1d4021d05d2ae40fec964a5f33d3730c';
|
||||
|
||||
/// See also [ShakeDetector].
|
||||
@ProviderFor(ShakeDetector)
|
||||
final shakeDetectorProvider =
|
||||
AutoDisposeNotifierProvider<ShakeDetector, core.ShakeDetector?>.internal(
|
||||
ShakeDetector.new,
|
||||
name: r'shakeDetectorProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$shakeDetectorHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
typedef _$ShakeDetector = AutoDisposeNotifier<core.ShakeDetector?>;
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package
|
||||
abstract class _$ShakeDetector extends $Notifier<core.ShakeDetector?> {
|
||||
core.ShakeDetector? build();
|
||||
@$mustCallSuper
|
||||
@override
|
||||
void runBuild() {
|
||||
final ref = this.ref as $Ref<core.ShakeDetector?, core.ShakeDetector?>;
|
||||
final element =
|
||||
ref.element
|
||||
as $ClassProviderElement<
|
||||
AnyNotifier<core.ShakeDetector?, core.ShakeDetector?>,
|
||||
core.ShakeDetector?,
|
||||
Object?,
|
||||
Object?
|
||||
>;
|
||||
element.handleCreate(ref, build);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -94,9 +94,7 @@ class SleepTimer {
|
|||
}
|
||||
|
||||
/// starts the timer with the given duration or the default duration
|
||||
void startCountDown([
|
||||
Duration? forDuration,
|
||||
]) {
|
||||
void startCountDown([Duration? forDuration]) {
|
||||
clearCountDownTimer();
|
||||
duration = forDuration ?? duration;
|
||||
timer = Timer(duration, () {
|
||||
|
|
|
|||
|
|
@ -6,20 +6,57 @@ part of 'sleep_timer_provider.dart';
|
|||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
|
||||
@ProviderFor(SleepTimer)
|
||||
final sleepTimerProvider = SleepTimerProvider._();
|
||||
|
||||
final class SleepTimerProvider
|
||||
extends $NotifierProvider<SleepTimer, core.SleepTimer?> {
|
||||
SleepTimerProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
retry: null,
|
||||
name: r'sleepTimerProvider',
|
||||
isAutoDispose: false,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$sleepTimerHash();
|
||||
|
||||
@$internal
|
||||
@override
|
||||
SleepTimer create() => SleepTimer();
|
||||
|
||||
/// {@macro riverpod.override_with_value}
|
||||
Override overrideWithValue(core.SleepTimer? value) {
|
||||
return $ProviderOverride(
|
||||
origin: this,
|
||||
providerOverride: $SyncValueProvider<core.SleepTimer?>(value),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
String _$sleepTimerHash() => r'2679454a217d0630a833d730557ab4e4feac2e56';
|
||||
|
||||
/// See also [SleepTimer].
|
||||
@ProviderFor(SleepTimer)
|
||||
final sleepTimerProvider =
|
||||
NotifierProvider<SleepTimer, core.SleepTimer?>.internal(
|
||||
SleepTimer.new,
|
||||
name: r'sleepTimerProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product') ? null : _$sleepTimerHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
typedef _$SleepTimer = Notifier<core.SleepTimer?>;
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package
|
||||
abstract class _$SleepTimer extends $Notifier<core.SleepTimer?> {
|
||||
core.SleepTimer? build();
|
||||
@$mustCallSuper
|
||||
@override
|
||||
void runBuild() {
|
||||
final ref = this.ref as $Ref<core.SleepTimer?, core.SleepTimer?>;
|
||||
final element =
|
||||
ref.element
|
||||
as $ClassProviderElement<
|
||||
AnyNotifier<core.SleepTimer?, core.SleepTimer?>,
|
||||
core.SleepTimer?,
|
||||
Object?,
|
||||
Object?
|
||||
>;
|
||||
element.handleCreate(ref, build);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,9 +13,7 @@ import 'package:vaani/settings/app_settings_provider.dart';
|
|||
import 'package:vaani/shared/extensions/duration_format.dart';
|
||||
|
||||
class SleepTimerButton extends HookConsumerWidget {
|
||||
const SleepTimerButton({
|
||||
super.key,
|
||||
});
|
||||
const SleepTimerButton({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
|
|
@ -47,8 +45,9 @@ class SleepTimerButton extends HookConsumerWidget {
|
|||
);
|
||||
pendingPlayerModals--;
|
||||
ref.read(sleepTimerProvider.notifier).setTimer(durationState.value);
|
||||
appLogger
|
||||
.fine('Sleep Timer dialog closed with ${durationState.value}');
|
||||
appLogger.fine(
|
||||
'Sleep Timer dialog closed with ${durationState.value}',
|
||||
);
|
||||
},
|
||||
child: AnimatedSwitcher(
|
||||
duration: const Duration(milliseconds: 300),
|
||||
|
|
@ -57,9 +56,7 @@ class SleepTimerButton extends HookConsumerWidget {
|
|||
Symbols.bedtime,
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
)
|
||||
: RemainingSleepTimeDisplay(
|
||||
timer: sleepTimer,
|
||||
),
|
||||
: RemainingSleepTimeDisplay(timer: sleepTimer),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
|
@ -67,10 +64,7 @@ class SleepTimerButton extends HookConsumerWidget {
|
|||
}
|
||||
|
||||
class SleepTimerBottomSheet extends HookConsumerWidget {
|
||||
const SleepTimerBottomSheet({
|
||||
super.key,
|
||||
this.onDurationSelected,
|
||||
});
|
||||
const SleepTimerBottomSheet({super.key, this.onDurationSelected});
|
||||
|
||||
final void Function(Duration?)? onDurationSelected;
|
||||
|
||||
|
|
@ -91,8 +85,9 @@ class SleepTimerBottomSheet extends HookConsumerWidget {
|
|||
];
|
||||
|
||||
final scrollController = useFixedExtentScrollController(
|
||||
initialItem:
|
||||
allPossibleDurations.indexOf(sleepTimer?.duration ?? minDuration),
|
||||
initialItem: allPossibleDurations.indexOf(
|
||||
sleepTimer?.duration ?? minDuration,
|
||||
),
|
||||
);
|
||||
|
||||
final durationState = useState<Duration>(
|
||||
|
|
@ -100,13 +95,10 @@ class SleepTimerBottomSheet extends HookConsumerWidget {
|
|||
);
|
||||
|
||||
// useEffect to rebuild the sleep timer when the duration changes
|
||||
useEffect(
|
||||
() {
|
||||
onDurationSelected?.call(durationState.value);
|
||||
return null;
|
||||
},
|
||||
[durationState.value],
|
||||
);
|
||||
useEffect(() {
|
||||
onDurationSelected?.call(durationState.value);
|
||||
return null;
|
||||
}, [durationState.value]);
|
||||
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
|
|
@ -171,18 +163,19 @@ class SleepTimerBottomSheet extends HookConsumerWidget {
|
|||
(timerDuration) => TextButton(
|
||||
style: timerDuration == durationState.value
|
||||
? TextButton.styleFrom(
|
||||
backgroundColor:
|
||||
Theme.of(context).colorScheme.primaryContainer,
|
||||
foregroundColor: Theme.of(context)
|
||||
.colorScheme
|
||||
.onPrimaryContainer,
|
||||
backgroundColor: Theme.of(
|
||||
context,
|
||||
).colorScheme.primaryContainer,
|
||||
foregroundColor: Theme.of(
|
||||
context,
|
||||
).colorScheme.onPrimaryContainer,
|
||||
)
|
||||
// border if not selected
|
||||
: TextButton.styleFrom(
|
||||
side: BorderSide(
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.primaryContainer,
|
||||
color: Theme.of(
|
||||
context,
|
||||
).colorScheme.primaryContainer,
|
||||
),
|
||||
),
|
||||
onPressed: () async {
|
||||
|
|
@ -215,10 +208,7 @@ class SleepTimerBottomSheet extends HookConsumerWidget {
|
|||
}
|
||||
|
||||
class RemainingSleepTimeDisplay extends HookConsumerWidget {
|
||||
const RemainingSleepTimeDisplay({
|
||||
super.key,
|
||||
required this.timer,
|
||||
});
|
||||
const RemainingSleepTimeDisplay({super.key, required this.timer});
|
||||
|
||||
final SleepTimer timer;
|
||||
|
||||
|
|
@ -230,17 +220,14 @@ class RemainingSleepTimeDisplay extends HookConsumerWidget {
|
|||
color: Theme.of(context).colorScheme.primary,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 8,
|
||||
vertical: 4,
|
||||
),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
||||
child: Text(
|
||||
timer.timer == null
|
||||
? timer.duration.smartBinaryFormat
|
||||
: remainingTime?.smartBinaryFormat ?? '',
|
||||
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
||||
color: Theme.of(context).colorScheme.onPrimary,
|
||||
),
|
||||
color: Theme.of(context).colorScheme.onPrimary,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
@ -272,8 +259,9 @@ class SleepTimerWheel extends StatelessWidget {
|
|||
icon: const Icon(Icons.remove),
|
||||
onPressed: () {
|
||||
// animate to index - 1
|
||||
final index = availableDurations
|
||||
.indexOf(durationState.value ?? Duration.zero);
|
||||
final index = availableDurations.indexOf(
|
||||
durationState.value ?? Duration.zero,
|
||||
);
|
||||
if (index > 0) {
|
||||
scrollController.animateToItem(
|
||||
index - 1,
|
||||
|
|
@ -289,14 +277,13 @@ class SleepTimerWheel extends StatelessWidget {
|
|||
controller: scrollController,
|
||||
scrollDirection: Axis.horizontal,
|
||||
itemExtent: itemExtent,
|
||||
diameterRatio: 1.5, squeeze: 1.2,
|
||||
diameterRatio: 1.5,
|
||||
squeeze: 1.2,
|
||||
// useMagnifier: true,
|
||||
// magnification: 1.5,
|
||||
physics: const FixedExtentScrollPhysics(),
|
||||
children: availableDurations
|
||||
.map(
|
||||
(duration) => DurationLine(duration: duration),
|
||||
)
|
||||
.map((duration) => DurationLine(duration: duration))
|
||||
.toList(),
|
||||
onSelectedItemChanged: (index) {
|
||||
durationState.value = availableDurations[index];
|
||||
|
|
@ -310,8 +297,9 @@ class SleepTimerWheel extends StatelessWidget {
|
|||
icon: const Icon(Icons.add),
|
||||
onPressed: () {
|
||||
// animate to index + 1
|
||||
final index = availableDurations
|
||||
.indexOf(durationState.value ?? Duration.zero);
|
||||
final index = availableDurations.indexOf(
|
||||
durationState.value ?? Duration.zero,
|
||||
);
|
||||
if (index < availableDurations.length - 1) {
|
||||
scrollController.animateToItem(
|
||||
index + 1,
|
||||
|
|
@ -327,10 +315,7 @@ class SleepTimerWheel extends StatelessWidget {
|
|||
}
|
||||
|
||||
class DurationLine extends StatelessWidget {
|
||||
const DurationLine({
|
||||
super.key,
|
||||
required this.duration,
|
||||
});
|
||||
const DurationLine({super.key, required this.duration});
|
||||
|
||||
final Duration duration;
|
||||
|
||||
|
|
@ -345,8 +330,8 @@ class DurationLine extends StatelessWidget {
|
|||
width: duration.inMinutes % 5 == 0
|
||||
? 3
|
||||
: duration.inMinutes % 2.5 == 0
|
||||
? 2
|
||||
: 0.5,
|
||||
? 2
|
||||
: 0.5,
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -20,16 +20,12 @@ import 'package:vaani/shared/extensions/obfuscation.dart' show ObfuscateSet;
|
|||
import 'package:vaani/shared/widgets/add_new_server.dart' show AddNewServer;
|
||||
|
||||
class ServerManagerPage extends HookConsumerWidget {
|
||||
const ServerManagerPage({
|
||||
super.key,
|
||||
});
|
||||
const ServerManagerPage({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('Manage Accounts'),
|
||||
),
|
||||
appBar: AppBar(title: const Text('Manage Accounts')),
|
||||
body: Center(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
|
|
@ -41,9 +37,7 @@ class ServerManagerPage extends HookConsumerWidget {
|
|||
}
|
||||
|
||||
class ServerManagerBody extends HookConsumerWidget {
|
||||
const ServerManagerBody({
|
||||
super.key,
|
||||
});
|
||||
const ServerManagerBody({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
|
|
@ -61,9 +55,7 @@ class ServerManagerBody extends HookConsumerWidget {
|
|||
// crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
const Text(
|
||||
'Registered Servers',
|
||||
),
|
||||
const Text('Registered Servers'),
|
||||
Expanded(
|
||||
child: ListView.builder(
|
||||
itemCount: registeredServers.length,
|
||||
|
|
@ -76,21 +68,17 @@ class ServerManagerBody extends HookConsumerWidget {
|
|||
'Users: ${availableUsers.where((element) => element.server == registeredServer).length}',
|
||||
),
|
||||
// children are list of users of this server
|
||||
children: availableUsers
|
||||
.where(
|
||||
(element) => element.server == registeredServer,
|
||||
)
|
||||
.map<Widget>(
|
||||
(e) => AvailableUserTile(user: e),
|
||||
)
|
||||
.nonNulls
|
||||
.toList()
|
||||
|
||||
// add buttons of delete server and add user to server at the end
|
||||
..addAll([
|
||||
AddUserTile(server: registeredServer),
|
||||
DeleteServerTile(server: registeredServer),
|
||||
]),
|
||||
children:
|
||||
availableUsers
|
||||
.where((element) => element.server == registeredServer)
|
||||
.map<Widget>((e) => AvailableUserTile(user: e))
|
||||
.nonNulls
|
||||
.toList()
|
||||
// add buttons of delete server and add user to server at the end
|
||||
..addAll([
|
||||
AddUserTile(server: registeredServer),
|
||||
DeleteServerTile(server: registeredServer),
|
||||
]),
|
||||
);
|
||||
},
|
||||
),
|
||||
|
|
@ -111,28 +99,24 @@ class ServerManagerBody extends HookConsumerWidget {
|
|||
final newServer = model.AudiobookShelfServer(
|
||||
serverUrl: makeBaseUrl(serverURIController.text),
|
||||
);
|
||||
ref.read(audiobookShelfServerProvider.notifier).addServer(
|
||||
newServer,
|
||||
);
|
||||
ref.read(apiSettingsProvider.notifier).updateState(
|
||||
apiSettings.copyWith(
|
||||
activeServer: newServer,
|
||||
),
|
||||
ref
|
||||
.read(audiobookShelfServerProvider.notifier)
|
||||
.addServer(newServer);
|
||||
ref
|
||||
.read(apiSettingsProvider.notifier)
|
||||
.updateState(
|
||||
apiSettings.copyWith(activeServer: newServer),
|
||||
);
|
||||
serverURIController.clear();
|
||||
} on ServerAlreadyExistsException catch (e) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(e.toString()),
|
||||
),
|
||||
);
|
||||
ScaffoldMessenger.of(
|
||||
context,
|
||||
).showSnackBar(SnackBar(content: Text(e.toString())));
|
||||
}
|
||||
} else {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text('Invalid URL'),
|
||||
),
|
||||
);
|
||||
ScaffoldMessenger.of(
|
||||
context,
|
||||
).showSnackBar(const SnackBar(content: Text('Invalid URL')));
|
||||
}
|
||||
},
|
||||
),
|
||||
|
|
@ -144,10 +128,7 @@ class ServerManagerBody extends HookConsumerWidget {
|
|||
}
|
||||
|
||||
class DeleteServerTile extends HookConsumerWidget {
|
||||
const DeleteServerTile({
|
||||
super.key,
|
||||
required this.server,
|
||||
});
|
||||
const DeleteServerTile({super.key, required this.server});
|
||||
|
||||
final model.AudiobookShelfServer server;
|
||||
|
||||
|
|
@ -167,9 +148,7 @@ class DeleteServerTile extends HookConsumerWidget {
|
|||
child: Text.rich(
|
||||
TextSpan(
|
||||
children: [
|
||||
const TextSpan(
|
||||
text: 'This will remove the server ',
|
||||
),
|
||||
const TextSpan(text: 'This will remove the server '),
|
||||
TextSpan(
|
||||
text: server.serverUrl.host,
|
||||
style: TextStyle(
|
||||
|
|
@ -194,13 +173,8 @@ class DeleteServerTile extends HookConsumerWidget {
|
|||
TextButton(
|
||||
onPressed: () {
|
||||
ref
|
||||
.read(
|
||||
audiobookShelfServerProvider.notifier,
|
||||
)
|
||||
.removeServer(
|
||||
server,
|
||||
removeUsers: true,
|
||||
);
|
||||
.read(audiobookShelfServerProvider.notifier)
|
||||
.removeServer(server, removeUsers: true);
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
child: const Text('Delete'),
|
||||
|
|
@ -215,10 +189,7 @@ class DeleteServerTile extends HookConsumerWidget {
|
|||
}
|
||||
|
||||
class AddUserTile extends HookConsumerWidget {
|
||||
const AddUserTile({
|
||||
super.key,
|
||||
required this.server,
|
||||
});
|
||||
const AddUserTile({super.key, required this.server});
|
||||
|
||||
final model.AudiobookShelfServer server;
|
||||
|
||||
|
|
@ -252,10 +223,12 @@ class AddUserTile extends HookConsumerWidget {
|
|||
label: 'Switch',
|
||||
onPressed: () {
|
||||
// Switch to the new user
|
||||
ref.read(apiSettingsProvider.notifier).updateState(
|
||||
ref.read(apiSettingsProvider).copyWith(
|
||||
activeUser: user,
|
||||
),
|
||||
ref
|
||||
.read(apiSettingsProvider.notifier)
|
||||
.updateState(
|
||||
ref
|
||||
.read(apiSettingsProvider)
|
||||
.copyWith(activeUser: user),
|
||||
);
|
||||
context.goNamed(Routes.home.name);
|
||||
},
|
||||
|
|
@ -283,10 +256,7 @@ class AddUserTile extends HookConsumerWidget {
|
|||
}
|
||||
|
||||
class AvailableUserTile extends HookConsumerWidget {
|
||||
const AvailableUserTile({
|
||||
super.key,
|
||||
required this.user,
|
||||
});
|
||||
const AvailableUserTile({super.key, required this.user});
|
||||
|
||||
final model.AuthenticatedUser user;
|
||||
|
||||
|
|
@ -303,18 +273,14 @@ class AvailableUserTile extends HookConsumerWidget {
|
|||
onTap: apiSettings.activeUser == user
|
||||
? null
|
||||
: () {
|
||||
ref.read(apiSettingsProvider.notifier).updateState(
|
||||
apiSettings.copyWith(
|
||||
activeUser: user,
|
||||
),
|
||||
);
|
||||
ref
|
||||
.read(apiSettingsProvider.notifier)
|
||||
.updateState(apiSettings.copyWith(activeUser: user));
|
||||
// pop all routes and go to the home page
|
||||
// while (context.canPop()) {
|
||||
// context.pop();
|
||||
// }
|
||||
context.goNamed(
|
||||
Routes.home.name,
|
||||
);
|
||||
context.goNamed(Routes.home.name);
|
||||
},
|
||||
trailing: IconButton(
|
||||
icon: const Icon(Icons.delete),
|
||||
|
|
@ -337,9 +303,7 @@ class AvailableUserTile extends HookConsumerWidget {
|
|||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
),
|
||||
const TextSpan(
|
||||
text: ' from this app.',
|
||||
),
|
||||
const TextSpan(text: ' from this app.'),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
|
@ -353,9 +317,7 @@ class AvailableUserTile extends HookConsumerWidget {
|
|||
TextButton(
|
||||
onPressed: () {
|
||||
ref
|
||||
.read(
|
||||
authenticatedUsersProvider.notifier,
|
||||
)
|
||||
.read(authenticatedUsersProvider.notifier)
|
||||
.removeUser(user);
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
|
|
|
|||
|
|
@ -11,10 +11,7 @@ import 'package:flutter/foundation.dart';
|
|||
import 'package:vaani/main.dart' show appLogger;
|
||||
|
||||
class LibrarySwitchChip extends HookConsumerWidget {
|
||||
const LibrarySwitchChip({
|
||||
super.key,
|
||||
required this.libraries,
|
||||
});
|
||||
const LibrarySwitchChip({super.key, required this.libraries});
|
||||
final List<Library> libraries;
|
||||
|
||||
@override
|
||||
|
|
@ -26,30 +23,22 @@ class LibrarySwitchChip extends HookConsumerWidget {
|
|||
AbsIcons.getIconByName(
|
||||
apiSettings.activeLibraryId != null
|
||||
? libraries
|
||||
.firstWhere(
|
||||
(lib) => lib.id == apiSettings.activeLibraryId,
|
||||
)
|
||||
.icon
|
||||
.firstWhere((lib) => lib.id == apiSettings.activeLibraryId)
|
||||
.icon
|
||||
: libraries.first.icon,
|
||||
),
|
||||
), // Replace with your icon
|
||||
label: const Text('Change Library'),
|
||||
// Enable only if libraries are loaded and not empty
|
||||
onPressed: libraries.isNotEmpty
|
||||
? () => showLibrarySwitcher(
|
||||
context,
|
||||
ref,
|
||||
)
|
||||
? () => showLibrarySwitcher(context, ref)
|
||||
: null, // Disable if no libraries
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// --- Helper Function to Show the Switcher ---
|
||||
void showLibrarySwitcher(
|
||||
BuildContext context,
|
||||
WidgetRef ref,
|
||||
) {
|
||||
void showLibrarySwitcher(BuildContext context, WidgetRef ref) {
|
||||
final content = _LibrarySelectionContent();
|
||||
|
||||
// --- Platform-Specific UI ---
|
||||
|
|
@ -209,7 +198,9 @@ class _LibrarySelectionContent extends ConsumerWidget {
|
|||
// Get current settings state
|
||||
final currentSettings = ref.read(apiSettingsProvider);
|
||||
// Update the active library ID
|
||||
ref.read(apiSettingsProvider.notifier).updateState(
|
||||
ref
|
||||
.read(apiSettingsProvider.notifier)
|
||||
.updateState(
|
||||
currentSettings.copyWith(activeLibraryId: library.id),
|
||||
);
|
||||
// Close the dialog/bottom sheet
|
||||
|
|
|
|||
|
|
@ -12,9 +12,7 @@ import 'package:vaani/shared/widgets/not_implemented.dart';
|
|||
import 'package:vaani/shared/widgets/vaani_logo.dart';
|
||||
|
||||
class YouPage extends HookConsumerWidget {
|
||||
const YouPage({
|
||||
super.key,
|
||||
});
|
||||
const YouPage({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
|
|
@ -88,8 +86,9 @@ class YouPage extends HookConsumerWidget {
|
|||
// Maybe show error details or allow retry
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content:
|
||||
Text('Failed to load libraries: $error'),
|
||||
content: Text(
|
||||
'Failed to load libraries: $error',
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
|
|
@ -159,9 +158,7 @@ class YouPage extends HookConsumerWidget {
|
|||
Theme.of(context).colorScheme.primary,
|
||||
BlendMode.srcIn,
|
||||
),
|
||||
child: const VaaniLogo(
|
||||
size: 48,
|
||||
),
|
||||
child: const VaaniLogo(size: 48),
|
||||
),
|
||||
),
|
||||
],
|
||||
|
|
@ -176,9 +173,7 @@ class YouPage extends HookConsumerWidget {
|
|||
}
|
||||
|
||||
class UserBar extends HookConsumerWidget {
|
||||
const UserBar({
|
||||
super.key,
|
||||
});
|
||||
const UserBar({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
|
|
@ -217,8 +212,9 @@ class UserBar extends HookConsumerWidget {
|
|||
Text(
|
||||
api.baseUrl.toString(),
|
||||
style: textTheme.bodyMedium?.copyWith(
|
||||
color:
|
||||
themeData.colorScheme.onSurface.withValues(alpha: 0.6),
|
||||
color: themeData.colorScheme.onSurface.withValues(
|
||||
alpha: 0.6,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
|
|
|
|||
|
|
@ -14,10 +14,7 @@ import 'package:flutter/material.dart';
|
|||
class InactiveFocusScopeObserver extends StatefulWidget {
|
||||
final Widget child;
|
||||
|
||||
const InactiveFocusScopeObserver({
|
||||
super.key,
|
||||
required this.child,
|
||||
});
|
||||
const InactiveFocusScopeObserver({super.key, required this.child});
|
||||
|
||||
@override
|
||||
State<InactiveFocusScopeObserver> createState() =>
|
||||
|
|
@ -39,10 +36,8 @@ class _InactiveFocusScopeObserverState
|
|||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => FocusScope(
|
||||
node: _focusScope,
|
||||
child: widget.child,
|
||||
);
|
||||
Widget build(BuildContext context) =>
|
||||
FocusScope(node: _focusScope, child: widget.child);
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
|
|
|
|||
|
|
@ -33,11 +33,7 @@ void main() async {
|
|||
await configurePlayer();
|
||||
|
||||
// run the app
|
||||
runApp(
|
||||
const ProviderScope(
|
||||
child: _EagerInitialization(child: MyApp()),
|
||||
),
|
||||
);
|
||||
runApp(const ProviderScope(child: _EagerInitialization(child: MyApp())));
|
||||
}
|
||||
|
||||
var routerConfig = const MyAppRouter().config;
|
||||
|
|
@ -65,20 +61,17 @@ class MyApp extends ConsumerWidget {
|
|||
themeSettings.highContrast || MediaQuery.of(context).highContrast;
|
||||
|
||||
if (shouldUseHighContrast) {
|
||||
lightColorScheme = lightColorScheme.copyWith(
|
||||
surface: Colors.white,
|
||||
);
|
||||
darkColorScheme = darkColorScheme.copyWith(
|
||||
surface: Colors.black,
|
||||
);
|
||||
lightColorScheme = lightColorScheme.copyWith(surface: Colors.white);
|
||||
darkColorScheme = darkColorScheme.copyWith(surface: Colors.black);
|
||||
}
|
||||
|
||||
if (themeSettings.useMaterialThemeFromSystem) {
|
||||
var themes =
|
||||
ref.watch(systemThemeProvider(highContrast: shouldUseHighContrast));
|
||||
if (themes.valueOrNull != null) {
|
||||
lightColorScheme = themes.valueOrNull!.$1;
|
||||
darkColorScheme = themes.valueOrNull!.$2;
|
||||
var themes = ref.watch(
|
||||
systemThemeProvider(highContrast: shouldUseHighContrast),
|
||||
);
|
||||
if (themes.value != null) {
|
||||
lightColorScheme = themes.value!.$1;
|
||||
darkColorScheme = themes.value!.$2;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -100,9 +93,9 @@ class MyApp extends ConsumerWidget {
|
|||
brightness: Brightness.dark,
|
||||
),
|
||||
);
|
||||
if (themeLight.valueOrNull != null && themeDark.valueOrNull != null) {
|
||||
lightColorScheme = themeLight.valueOrNull!;
|
||||
darkColorScheme = themeDark.valueOrNull!;
|
||||
if (themeLight.value != null && themeDark.value != null) {
|
||||
lightColorScheme = themeLight.value!;
|
||||
darkColorScheme = themeDark.value!;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
|
|
|
|||
|
|
@ -52,7 +52,9 @@ class HomePage extends HookConsumerWidget {
|
|||
// try again button
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
ref.read(apiSettingsProvider.notifier).updateState(
|
||||
ref
|
||||
.read(apiSettingsProvider.notifier)
|
||||
.updateState(
|
||||
apiSettings.copyWith(activeLibraryId: null),
|
||||
);
|
||||
ref.invalidate(personalizedViewProvider);
|
||||
|
|
@ -66,24 +68,25 @@ class HomePage extends HookConsumerWidget {
|
|||
final shelvesToDisplay = data
|
||||
// .where((element) => !element.id.contains('discover'))
|
||||
.map((shelf) {
|
||||
appLogger.fine('building shelf ${shelf.label}');
|
||||
// check if showPlayButton is enabled for the shelf
|
||||
// using the id of the shelf
|
||||
final showPlayButton = switch (shelf.id) {
|
||||
'continue-listening' =>
|
||||
homePageSettings.showPlayButtonOnContinueListeningShelf,
|
||||
'continue-series' =>
|
||||
homePageSettings.showPlayButtonOnContinueSeriesShelf,
|
||||
'listen-again' =>
|
||||
homePageSettings.showPlayButtonOnListenAgainShelf,
|
||||
_ => homePageSettings.showPlayButtonOnAllRemainingShelves,
|
||||
};
|
||||
return HomeShelf(
|
||||
title: shelf.label,
|
||||
shelf: shelf,
|
||||
showPlayButton: showPlayButton,
|
||||
);
|
||||
}).toList();
|
||||
appLogger.fine('building shelf ${shelf.label}');
|
||||
// check if showPlayButton is enabled for the shelf
|
||||
// using the id of the shelf
|
||||
final showPlayButton = switch (shelf.id) {
|
||||
'continue-listening' =>
|
||||
homePageSettings.showPlayButtonOnContinueListeningShelf,
|
||||
'continue-series' =>
|
||||
homePageSettings.showPlayButtonOnContinueSeriesShelf,
|
||||
'listen-again' =>
|
||||
homePageSettings.showPlayButtonOnListenAgainShelf,
|
||||
_ => homePageSettings.showPlayButtonOnAllRemainingShelves,
|
||||
};
|
||||
return HomeShelf(
|
||||
title: shelf.label,
|
||||
shelf: shelf,
|
||||
showPlayButton: showPlayButton,
|
||||
);
|
||||
})
|
||||
.toList();
|
||||
return RefreshIndicator(
|
||||
onRefresh: () async {
|
||||
return ref.refresh(personalizedViewProvider);
|
||||
|
|
@ -132,10 +135,6 @@ class HomePageSkeleton extends StatelessWidget {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return const Scaffold(
|
||||
body: Center(
|
||||
child: CircularProgressIndicator(),
|
||||
),
|
||||
);
|
||||
return const Scaffold(body: Center(child: CircularProgressIndicator()));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,9 @@ class LibraryPage extends HookConsumerWidget {
|
|||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
// set the library id as the active library
|
||||
if (libraryId != null) {
|
||||
ref.read(apiSettingsProvider.notifier).updateState(
|
||||
ref
|
||||
.read(apiSettingsProvider.notifier)
|
||||
.updateState(
|
||||
ref.watch(apiSettingsProvider).copyWith(activeLibraryId: libraryId),
|
||||
);
|
||||
}
|
||||
|
|
@ -48,12 +50,10 @@ class LibraryPage extends HookConsumerWidget {
|
|||
final shelvesToDisplay = data
|
||||
// .where((element) => !element.id.contains('discover'))
|
||||
.map((shelf) {
|
||||
appLogger.fine('building shelf ${shelf.label}');
|
||||
return HomeShelf(
|
||||
title: shelf.label,
|
||||
shelf: shelf,
|
||||
);
|
||||
}).toList();
|
||||
appLogger.fine('building shelf ${shelf.label}');
|
||||
return HomeShelf(title: shelf.label, shelf: shelf);
|
||||
})
|
||||
.toList();
|
||||
return RefreshIndicator(
|
||||
onRefresh: () async {
|
||||
return ref.refresh(personalizedViewProvider);
|
||||
|
|
@ -85,10 +85,6 @@ class LibraryPageSkeleton extends StatelessWidget {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return const Scaffold(
|
||||
body: Center(
|
||||
child: CircularProgressIndicator(),
|
||||
),
|
||||
);
|
||||
return const Scaffold(body: Center(child: CircularProgressIndicator()));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,14 +3,8 @@
|
|||
part of 'router.dart';
|
||||
|
||||
class Routes {
|
||||
static const home = _SimpleRoute(
|
||||
pathName: '',
|
||||
name: 'home',
|
||||
);
|
||||
static const onboarding = _SimpleRoute(
|
||||
pathName: 'login',
|
||||
name: 'onboarding',
|
||||
);
|
||||
static const home = _SimpleRoute(pathName: '', name: 'home');
|
||||
static const onboarding = _SimpleRoute(pathName: 'login', name: 'onboarding');
|
||||
static const library = _SimpleRoute(
|
||||
pathName: 'library',
|
||||
pathParamName: 'libraryId',
|
||||
|
|
@ -23,10 +17,7 @@ class Routes {
|
|||
);
|
||||
|
||||
// Local settings
|
||||
static const settings = _SimpleRoute(
|
||||
pathName: 'config',
|
||||
name: 'settings',
|
||||
);
|
||||
static const settings = _SimpleRoute(pathName: 'config', name: 'settings');
|
||||
static const themeSettings = _SimpleRoute(
|
||||
pathName: 'theme',
|
||||
name: 'themeSettings',
|
||||
|
|
@ -64,10 +55,7 @@ class Routes {
|
|||
name: 'search',
|
||||
// parentRoute: library,
|
||||
);
|
||||
static const explore = _SimpleRoute(
|
||||
pathName: 'explore',
|
||||
name: 'explore',
|
||||
);
|
||||
static const explore = _SimpleRoute(pathName: 'explore', name: 'explore');
|
||||
|
||||
// downloads
|
||||
static const downloads = _SimpleRoute(
|
||||
|
|
@ -83,10 +71,7 @@ class Routes {
|
|||
);
|
||||
|
||||
// you page for the user
|
||||
static const you = _SimpleRoute(
|
||||
pathName: 'you',
|
||||
name: 'you',
|
||||
);
|
||||
static const you = _SimpleRoute(pathName: 'you', name: 'you');
|
||||
|
||||
// user management
|
||||
static const userManagement = _SimpleRoute(
|
||||
|
|
@ -102,10 +87,7 @@ class Routes {
|
|||
);
|
||||
|
||||
// logs page
|
||||
static const logs = _SimpleRoute(
|
||||
pathName: 'logs',
|
||||
name: 'logs',
|
||||
);
|
||||
static const logs = _SimpleRoute(pathName: 'logs', name: 'logs');
|
||||
}
|
||||
|
||||
// a class to store path
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ part 'library_item_extras.freezed.dart';
|
|||
/// [book] is the book that the item represents
|
||||
/// [heroTagSuffix] is the suffix to use for the hero tag to avoid conflicts
|
||||
@freezed
|
||||
class LibraryItemExtras with _$LibraryItemExtras {
|
||||
sealed class LibraryItemExtras with _$LibraryItemExtras {
|
||||
const factory LibraryItemExtras({
|
||||
BookMinified? book,
|
||||
@Default('') String heroTagSuffix,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
// coverage:ignore-file
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// coverage:ignore-file
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
|
||||
|
||||
|
|
@ -9,156 +9,260 @@ part of 'library_item_extras.dart';
|
|||
// FreezedGenerator
|
||||
// **************************************************************************
|
||||
|
||||
// dart format off
|
||||
T _$identity<T>(T value) => value;
|
||||
|
||||
final _privateConstructorUsedError = UnsupportedError(
|
||||
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models');
|
||||
|
||||
/// @nodoc
|
||||
mixin _$LibraryItemExtras {
|
||||
BookMinified? get book => throw _privateConstructorUsedError;
|
||||
String get heroTagSuffix => throw _privateConstructorUsedError;
|
||||
|
||||
/// Create a copy of LibraryItemExtras
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
$LibraryItemExtrasCopyWith<LibraryItemExtras> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
BookMinified? get book; String get heroTagSuffix;
|
||||
/// Create a copy of LibraryItemExtras
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
$LibraryItemExtrasCopyWith<LibraryItemExtras> get copyWith => _$LibraryItemExtrasCopyWithImpl<LibraryItemExtras>(this as LibraryItemExtras, _$identity);
|
||||
|
||||
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is LibraryItemExtras&&(identical(other.book, book) || other.book == book)&&(identical(other.heroTagSuffix, heroTagSuffix) || other.heroTagSuffix == heroTagSuffix));
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,book,heroTagSuffix);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'LibraryItemExtras(book: $book, heroTagSuffix: $heroTagSuffix)';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $LibraryItemExtrasCopyWith<$Res> {
|
||||
factory $LibraryItemExtrasCopyWith(
|
||||
LibraryItemExtras value, $Res Function(LibraryItemExtras) then) =
|
||||
_$LibraryItemExtrasCopyWithImpl<$Res, LibraryItemExtras>;
|
||||
@useResult
|
||||
$Res call({BookMinified? book, String heroTagSuffix});
|
||||
}
|
||||
abstract mixin class $LibraryItemExtrasCopyWith<$Res> {
|
||||
factory $LibraryItemExtrasCopyWith(LibraryItemExtras value, $Res Function(LibraryItemExtras) _then) = _$LibraryItemExtrasCopyWithImpl;
|
||||
@useResult
|
||||
$Res call({
|
||||
BookMinified? book, String heroTagSuffix
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
/// @nodoc
|
||||
class _$LibraryItemExtrasCopyWithImpl<$Res, $Val extends LibraryItemExtras>
|
||||
class _$LibraryItemExtrasCopyWithImpl<$Res>
|
||||
implements $LibraryItemExtrasCopyWith<$Res> {
|
||||
_$LibraryItemExtrasCopyWithImpl(this._value, this._then);
|
||||
_$LibraryItemExtrasCopyWithImpl(this._self, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
final LibraryItemExtras _self;
|
||||
final $Res Function(LibraryItemExtras) _then;
|
||||
|
||||
/// Create a copy of LibraryItemExtras
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? book = freezed,
|
||||
Object? heroTagSuffix = null,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
book: freezed == book
|
||||
? _value.book
|
||||
: book // ignore: cast_nullable_to_non_nullable
|
||||
as BookMinified?,
|
||||
heroTagSuffix: null == heroTagSuffix
|
||||
? _value.heroTagSuffix
|
||||
: heroTagSuffix // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
) as $Val);
|
||||
}
|
||||
/// Create a copy of LibraryItemExtras
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? book = freezed,Object? heroTagSuffix = null,}) {
|
||||
return _then(_self.copyWith(
|
||||
book: freezed == book ? _self.book : book // ignore: cast_nullable_to_non_nullable
|
||||
as BookMinified?,heroTagSuffix: null == heroTagSuffix ? _self.heroTagSuffix : heroTagSuffix // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
));
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$LibraryItemExtrasImplCopyWith<$Res>
|
||||
implements $LibraryItemExtrasCopyWith<$Res> {
|
||||
factory _$$LibraryItemExtrasImplCopyWith(_$LibraryItemExtrasImpl value,
|
||||
$Res Function(_$LibraryItemExtrasImpl) then) =
|
||||
__$$LibraryItemExtrasImplCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call({BookMinified? book, String heroTagSuffix});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$LibraryItemExtrasImplCopyWithImpl<$Res>
|
||||
extends _$LibraryItemExtrasCopyWithImpl<$Res, _$LibraryItemExtrasImpl>
|
||||
implements _$$LibraryItemExtrasImplCopyWith<$Res> {
|
||||
__$$LibraryItemExtrasImplCopyWithImpl(_$LibraryItemExtrasImpl _value,
|
||||
$Res Function(_$LibraryItemExtrasImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of LibraryItemExtras
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? book = freezed,
|
||||
Object? heroTagSuffix = null,
|
||||
}) {
|
||||
return _then(_$LibraryItemExtrasImpl(
|
||||
book: freezed == book
|
||||
? _value.book
|
||||
: book // ignore: cast_nullable_to_non_nullable
|
||||
as BookMinified?,
|
||||
heroTagSuffix: null == heroTagSuffix
|
||||
? _value.heroTagSuffix
|
||||
: heroTagSuffix // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
));
|
||||
}
|
||||
/// Adds pattern-matching-related methods to [LibraryItemExtras].
|
||||
extension LibraryItemExtrasPatterns on LibraryItemExtras {
|
||||
/// A variant of `map` that fallback to returning `orElse`.
|
||||
///
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case final Subclass value:
|
||||
/// return ...;
|
||||
/// case _:
|
||||
/// return orElse();
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _LibraryItemExtras value)? $default,{required TResult orElse(),}){
|
||||
final _that = this;
|
||||
switch (_that) {
|
||||
case _LibraryItemExtras() when $default != null:
|
||||
return $default(_that);case _:
|
||||
return orElse();
|
||||
|
||||
}
|
||||
}
|
||||
/// A `switch`-like method, using callbacks.
|
||||
///
|
||||
/// Callbacks receives the raw object, upcasted.
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case final Subclass value:
|
||||
/// return ...;
|
||||
/// case final Subclass2 value:
|
||||
/// return ...;
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _LibraryItemExtras value) $default,){
|
||||
final _that = this;
|
||||
switch (_that) {
|
||||
case _LibraryItemExtras():
|
||||
return $default(_that);}
|
||||
}
|
||||
/// A variant of `map` that fallback to returning `null`.
|
||||
///
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case final Subclass value:
|
||||
/// return ...;
|
||||
/// case _:
|
||||
/// return null;
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _LibraryItemExtras value)? $default,){
|
||||
final _that = this;
|
||||
switch (_that) {
|
||||
case _LibraryItemExtras() when $default != null:
|
||||
return $default(_that);case _:
|
||||
return null;
|
||||
|
||||
}
|
||||
}
|
||||
/// A variant of `when` that fallback to an `orElse` callback.
|
||||
///
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case Subclass(:final field):
|
||||
/// return ...;
|
||||
/// case _:
|
||||
/// return orElse();
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( BookMinified? book, String heroTagSuffix)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
switch (_that) {
|
||||
case _LibraryItemExtras() when $default != null:
|
||||
return $default(_that.book,_that.heroTagSuffix);case _:
|
||||
return orElse();
|
||||
|
||||
}
|
||||
}
|
||||
/// A `switch`-like method, using callbacks.
|
||||
///
|
||||
/// As opposed to `map`, this offers destructuring.
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case Subclass(:final field):
|
||||
/// return ...;
|
||||
/// case Subclass2(:final field2):
|
||||
/// return ...;
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( BookMinified? book, String heroTagSuffix) $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _LibraryItemExtras():
|
||||
return $default(_that.book,_that.heroTagSuffix);}
|
||||
}
|
||||
/// A variant of `when` that fallback to returning `null`
|
||||
///
|
||||
/// It is equivalent to doing:
|
||||
/// ```dart
|
||||
/// switch (sealedClass) {
|
||||
/// case Subclass(:final field):
|
||||
/// return ...;
|
||||
/// case _:
|
||||
/// return null;
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( BookMinified? book, String heroTagSuffix)? $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _LibraryItemExtras() when $default != null:
|
||||
return $default(_that.book,_that.heroTagSuffix);case _:
|
||||
return null;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$LibraryItemExtrasImpl implements _LibraryItemExtras {
|
||||
const _$LibraryItemExtrasImpl({this.book, this.heroTagSuffix = ''});
|
||||
|
||||
@override
|
||||
final BookMinified? book;
|
||||
@override
|
||||
@JsonKey()
|
||||
final String heroTagSuffix;
|
||||
class _LibraryItemExtras implements LibraryItemExtras {
|
||||
const _LibraryItemExtras({this.book, this.heroTagSuffix = ''});
|
||||
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'LibraryItemExtras(book: $book, heroTagSuffix: $heroTagSuffix)';
|
||||
}
|
||||
@override final BookMinified? book;
|
||||
@override@JsonKey() final String heroTagSuffix;
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$LibraryItemExtrasImpl &&
|
||||
(identical(other.book, book) || other.book == book) &&
|
||||
(identical(other.heroTagSuffix, heroTagSuffix) ||
|
||||
other.heroTagSuffix == heroTagSuffix));
|
||||
}
|
||||
/// Create a copy of LibraryItemExtras
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@pragma('vm:prefer-inline')
|
||||
_$LibraryItemExtrasCopyWith<_LibraryItemExtras> get copyWith => __$LibraryItemExtrasCopyWithImpl<_LibraryItemExtras>(this, _$identity);
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, book, heroTagSuffix);
|
||||
|
||||
/// Create a copy of LibraryItemExtras
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$LibraryItemExtrasImplCopyWith<_$LibraryItemExtrasImpl> get copyWith =>
|
||||
__$$LibraryItemExtrasImplCopyWithImpl<_$LibraryItemExtrasImpl>(
|
||||
this, _$identity);
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _LibraryItemExtras&&(identical(other.book, book) || other.book == book)&&(identical(other.heroTagSuffix, heroTagSuffix) || other.heroTagSuffix == heroTagSuffix));
|
||||
}
|
||||
|
||||
abstract class _LibraryItemExtras implements LibraryItemExtras {
|
||||
const factory _LibraryItemExtras(
|
||||
{final BookMinified? book,
|
||||
final String heroTagSuffix}) = _$LibraryItemExtrasImpl;
|
||||
|
||||
@override
|
||||
BookMinified? get book;
|
||||
@override
|
||||
String get heroTagSuffix;
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,book,heroTagSuffix);
|
||||
|
||||
/// Create a copy of LibraryItemExtras
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$LibraryItemExtrasImplCopyWith<_$LibraryItemExtrasImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
@override
|
||||
String toString() {
|
||||
return 'LibraryItemExtras(book: $book, heroTagSuffix: $heroTagSuffix)';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract mixin class _$LibraryItemExtrasCopyWith<$Res> implements $LibraryItemExtrasCopyWith<$Res> {
|
||||
factory _$LibraryItemExtrasCopyWith(_LibraryItemExtras value, $Res Function(_LibraryItemExtras) _then) = __$LibraryItemExtrasCopyWithImpl;
|
||||
@override @useResult
|
||||
$Res call({
|
||||
BookMinified? book, String heroTagSuffix
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
/// @nodoc
|
||||
class __$LibraryItemExtrasCopyWithImpl<$Res>
|
||||
implements _$LibraryItemExtrasCopyWith<$Res> {
|
||||
__$LibraryItemExtrasCopyWithImpl(this._self, this._then);
|
||||
|
||||
final _LibraryItemExtras _self;
|
||||
final $Res Function(_LibraryItemExtras) _then;
|
||||
|
||||
/// Create a copy of LibraryItemExtras
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? book = freezed,Object? heroTagSuffix = null,}) {
|
||||
return _then(_LibraryItemExtras(
|
||||
book: freezed == book ? _self.book : book // ignore: cast_nullable_to_non_nullable
|
||||
as BookMinified?,heroTagSuffix: null == heroTagSuffix ? _self.heroTagSuffix : heroTagSuffix // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// dart format on
|
||||
|
|
|
|||
|
|
@ -25,8 +25,9 @@ import 'transitions/slide.dart';
|
|||
|
||||
part 'constants.dart';
|
||||
|
||||
final GlobalKey<NavigatorState> rootNavigatorKey =
|
||||
GlobalKey<NavigatorState>(debugLabel: 'root');
|
||||
final GlobalKey<NavigatorState> rootNavigatorKey = GlobalKey<NavigatorState>(
|
||||
debugLabel: 'root',
|
||||
);
|
||||
final GlobalKey<NavigatorState> sectionHomeNavigatorKey =
|
||||
GlobalKey<NavigatorState>(debugLabel: 'HomeNavigator');
|
||||
|
||||
|
|
@ -35,34 +36,35 @@ class MyAppRouter {
|
|||
const MyAppRouter();
|
||||
|
||||
GoRouter get config => GoRouter(
|
||||
initialLocation: Routes.home.localPath,
|
||||
debugLogDiagnostics: true,
|
||||
initialLocation: Routes.home.localPath,
|
||||
debugLogDiagnostics: true,
|
||||
routes: [
|
||||
// sign in page
|
||||
GoRoute(
|
||||
path: Routes.onboarding.localPath,
|
||||
name: Routes.onboarding.name,
|
||||
builder: (context, state) => const OnboardingSinglePage(),
|
||||
routes: [
|
||||
// sign in page
|
||||
// open id callback
|
||||
GoRoute(
|
||||
path: Routes.onboarding.localPath,
|
||||
name: Routes.onboarding.name,
|
||||
builder: (context, state) => const OnboardingSinglePage(),
|
||||
routes: [
|
||||
// open id callback
|
||||
GoRoute(
|
||||
path: Routes.openIDCallback.pathName,
|
||||
name: Routes.openIDCallback.name,
|
||||
pageBuilder: handleCallback,
|
||||
),
|
||||
],
|
||||
),
|
||||
// callback for open id
|
||||
// need to duplicate because of https://github.com/flutter/flutter/issues/100624
|
||||
GoRoute(
|
||||
path: Routes.openIDCallback.localPath,
|
||||
// name: Routes.openIDCallback.name,
|
||||
// builder: handleCallback,
|
||||
path: Routes.openIDCallback.pathName,
|
||||
name: Routes.openIDCallback.name,
|
||||
pageBuilder: handleCallback,
|
||||
),
|
||||
// The main app shell
|
||||
StatefulShellRoute.indexedStack(
|
||||
builder: (
|
||||
],
|
||||
),
|
||||
// callback for open id
|
||||
// need to duplicate because of https://github.com/flutter/flutter/issues/100624
|
||||
GoRoute(
|
||||
path: Routes.openIDCallback.localPath,
|
||||
// name: Routes.openIDCallback.name,
|
||||
// builder: handleCallback,
|
||||
pageBuilder: handleCallback,
|
||||
),
|
||||
// The main app shell
|
||||
StatefulShellRoute.indexedStack(
|
||||
builder:
|
||||
(
|
||||
BuildContext context,
|
||||
GoRouterState state,
|
||||
StatefulNavigationShell navigationShell,
|
||||
|
|
@ -73,188 +75,187 @@ class MyAppRouter {
|
|||
// branches in a stateful way.
|
||||
return ScaffoldWithNavBar(navigationShell: navigationShell);
|
||||
},
|
||||
branches: <StatefulShellBranch>[
|
||||
// The route branch for the first tab of the bottom navigation bar.
|
||||
StatefulShellBranch(
|
||||
navigatorKey: sectionHomeNavigatorKey,
|
||||
routes: <RouteBase>[
|
||||
GoRoute(
|
||||
path: Routes.home.localPath,
|
||||
name: Routes.home.name,
|
||||
// builder: (context, state) => const HomePage(),
|
||||
pageBuilder: defaultPageBuilder(const HomePage()),
|
||||
),
|
||||
GoRoute(
|
||||
path: Routes.libraryItem.localPath,
|
||||
name: Routes.libraryItem.name,
|
||||
// builder: (context, state) {
|
||||
// final itemId = state
|
||||
// .pathParameters[Routes.libraryItem.pathParamName]!;
|
||||
// return LibraryItemPage(
|
||||
// itemId: itemId, extra: state.extra);
|
||||
// },
|
||||
pageBuilder: (context, state) {
|
||||
final itemId = state
|
||||
.pathParameters[Routes.libraryItem.pathParamName]!;
|
||||
final child =
|
||||
LibraryItemPage(itemId: itemId, extra: state.extra);
|
||||
return buildPageWithDefaultTransition(
|
||||
context: context,
|
||||
state: state,
|
||||
child: child,
|
||||
);
|
||||
},
|
||||
),
|
||||
// downloads page
|
||||
GoRoute(
|
||||
path: Routes.downloads.localPath,
|
||||
name: Routes.downloads.name,
|
||||
pageBuilder: defaultPageBuilder(const DownloadsPage()),
|
||||
),
|
||||
],
|
||||
branches: <StatefulShellBranch>[
|
||||
// The route branch for the first tab of the bottom navigation bar.
|
||||
StatefulShellBranch(
|
||||
navigatorKey: sectionHomeNavigatorKey,
|
||||
routes: <RouteBase>[
|
||||
GoRoute(
|
||||
path: Routes.home.localPath,
|
||||
name: Routes.home.name,
|
||||
// builder: (context, state) => const HomePage(),
|
||||
pageBuilder: defaultPageBuilder(const HomePage()),
|
||||
),
|
||||
|
||||
// Library page
|
||||
StatefulShellBranch(
|
||||
routes: <RouteBase>[
|
||||
GoRoute(
|
||||
path: Routes.libraryBrowser.localPath,
|
||||
name: Routes.libraryBrowser.name,
|
||||
pageBuilder: defaultPageBuilder(const LibraryBrowserPage()),
|
||||
),
|
||||
],
|
||||
GoRoute(
|
||||
path: Routes.libraryItem.localPath,
|
||||
name: Routes.libraryItem.name,
|
||||
// builder: (context, state) {
|
||||
// final itemId = state
|
||||
// .pathParameters[Routes.libraryItem.pathParamName]!;
|
||||
// return LibraryItemPage(
|
||||
// itemId: itemId, extra: state.extra);
|
||||
// },
|
||||
pageBuilder: (context, state) {
|
||||
final itemId =
|
||||
state.pathParameters[Routes.libraryItem.pathParamName]!;
|
||||
final child = LibraryItemPage(
|
||||
itemId: itemId,
|
||||
extra: state.extra,
|
||||
);
|
||||
return buildPageWithDefaultTransition(
|
||||
context: context,
|
||||
state: state,
|
||||
child: child,
|
||||
);
|
||||
},
|
||||
),
|
||||
// search/explore page
|
||||
StatefulShellBranch(
|
||||
routes: <RouteBase>[
|
||||
GoRoute(
|
||||
path: Routes.explore.localPath,
|
||||
name: Routes.explore.name,
|
||||
// builder: (context, state) => const ExplorePage(),
|
||||
pageBuilder: defaultPageBuilder(const ExplorePage()),
|
||||
),
|
||||
// search page
|
||||
GoRoute(
|
||||
path: Routes.search.localPath,
|
||||
name: Routes.search.name,
|
||||
// builder: (context, state) {
|
||||
// final libraryId = state
|
||||
// .pathParameters[Routes.library.pathParamName]!;
|
||||
// return LibrarySearchPage(
|
||||
// libraryId: libraryId,
|
||||
// extra: state.extra,
|
||||
// );
|
||||
// },
|
||||
pageBuilder: (context, state) {
|
||||
final queryParam = state.uri.queryParameters['q']!;
|
||||
final category = state.uri.queryParameters['category'];
|
||||
final child = SearchResultPage(
|
||||
extra: state.extra,
|
||||
query: queryParam,
|
||||
category: category != null
|
||||
? SearchResultCategory.values.firstWhere(
|
||||
(e) => e.toString().split('.').last == category,
|
||||
)
|
||||
: null,
|
||||
);
|
||||
return buildPageWithDefaultTransition(
|
||||
context: context,
|
||||
state: state,
|
||||
child: child,
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
// you page
|
||||
StatefulShellBranch(
|
||||
routes: <RouteBase>[
|
||||
GoRoute(
|
||||
path: Routes.you.localPath,
|
||||
name: Routes.you.name,
|
||||
pageBuilder: defaultPageBuilder(const YouPage()),
|
||||
),
|
||||
GoRoute(
|
||||
path: Routes.settings.localPath,
|
||||
name: Routes.settings.name,
|
||||
// builder: (context, state) => const AppSettingsPage(),
|
||||
pageBuilder: defaultPageBuilder(const AppSettingsPage()),
|
||||
routes: [
|
||||
GoRoute(
|
||||
path: Routes.themeSettings.pathName,
|
||||
name: Routes.themeSettings.name,
|
||||
pageBuilder: defaultPageBuilder(
|
||||
const ThemeSettingsPage(),
|
||||
),
|
||||
),
|
||||
GoRoute(
|
||||
path: Routes.autoSleepTimerSettings.pathName,
|
||||
name: Routes.autoSleepTimerSettings.name,
|
||||
pageBuilder: defaultPageBuilder(
|
||||
const AutoSleepTimerSettingsPage(),
|
||||
),
|
||||
),
|
||||
GoRoute(
|
||||
path: Routes.notificationSettings.pathName,
|
||||
name: Routes.notificationSettings.name,
|
||||
pageBuilder: defaultPageBuilder(
|
||||
const NotificationSettingsPage(),
|
||||
),
|
||||
),
|
||||
GoRoute(
|
||||
path: Routes.playerSettings.pathName,
|
||||
name: Routes.playerSettings.name,
|
||||
pageBuilder:
|
||||
defaultPageBuilder(const PlayerSettingsPage()),
|
||||
),
|
||||
GoRoute(
|
||||
path: Routes.shakeDetectorSettings.pathName,
|
||||
name: Routes.shakeDetectorSettings.name,
|
||||
pageBuilder: defaultPageBuilder(
|
||||
const ShakeDetectorSettingsPage(),
|
||||
),
|
||||
),
|
||||
GoRoute(
|
||||
path: Routes.homePageSettings.pathName,
|
||||
name: Routes.homePageSettings.name,
|
||||
pageBuilder: defaultPageBuilder(
|
||||
const HomePageSettingsPage(),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
GoRoute(
|
||||
path: Routes.userManagement.localPath,
|
||||
name: Routes.userManagement.name,
|
||||
// builder: (context, state) => const UserManagementPage(),
|
||||
pageBuilder: defaultPageBuilder(const ServerManagerPage()),
|
||||
),
|
||||
],
|
||||
// downloads page
|
||||
GoRoute(
|
||||
path: Routes.downloads.localPath,
|
||||
name: Routes.downloads.name,
|
||||
pageBuilder: defaultPageBuilder(const DownloadsPage()),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
// loggers page
|
||||
GoRoute(
|
||||
path: Routes.logs.localPath,
|
||||
name: Routes.logs.name,
|
||||
// builder: (context, state) => const LogsPage(),
|
||||
pageBuilder: defaultPageBuilder(const LogsPage()),
|
||||
// Library page
|
||||
StatefulShellBranch(
|
||||
routes: <RouteBase>[
|
||||
GoRoute(
|
||||
path: Routes.libraryBrowser.localPath,
|
||||
name: Routes.libraryBrowser.name,
|
||||
pageBuilder: defaultPageBuilder(const LibraryBrowserPage()),
|
||||
),
|
||||
],
|
||||
),
|
||||
// search/explore page
|
||||
StatefulShellBranch(
|
||||
routes: <RouteBase>[
|
||||
GoRoute(
|
||||
path: Routes.explore.localPath,
|
||||
name: Routes.explore.name,
|
||||
// builder: (context, state) => const ExplorePage(),
|
||||
pageBuilder: defaultPageBuilder(const ExplorePage()),
|
||||
),
|
||||
// search page
|
||||
GoRoute(
|
||||
path: Routes.search.localPath,
|
||||
name: Routes.search.name,
|
||||
// builder: (context, state) {
|
||||
// final libraryId = state
|
||||
// .pathParameters[Routes.library.pathParamName]!;
|
||||
// return LibrarySearchPage(
|
||||
// libraryId: libraryId,
|
||||
// extra: state.extra,
|
||||
// );
|
||||
// },
|
||||
pageBuilder: (context, state) {
|
||||
final queryParam = state.uri.queryParameters['q']!;
|
||||
final category = state.uri.queryParameters['category'];
|
||||
final child = SearchResultPage(
|
||||
extra: state.extra,
|
||||
query: queryParam,
|
||||
category: category != null
|
||||
? SearchResultCategory.values.firstWhere(
|
||||
(e) => e.toString().split('.').last == category,
|
||||
)
|
||||
: null,
|
||||
);
|
||||
return buildPageWithDefaultTransition(
|
||||
context: context,
|
||||
state: state,
|
||||
child: child,
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
// you page
|
||||
StatefulShellBranch(
|
||||
routes: <RouteBase>[
|
||||
GoRoute(
|
||||
path: Routes.you.localPath,
|
||||
name: Routes.you.name,
|
||||
pageBuilder: defaultPageBuilder(const YouPage()),
|
||||
),
|
||||
GoRoute(
|
||||
path: Routes.settings.localPath,
|
||||
name: Routes.settings.name,
|
||||
// builder: (context, state) => const AppSettingsPage(),
|
||||
pageBuilder: defaultPageBuilder(const AppSettingsPage()),
|
||||
routes: [
|
||||
GoRoute(
|
||||
path: Routes.themeSettings.pathName,
|
||||
name: Routes.themeSettings.name,
|
||||
pageBuilder: defaultPageBuilder(const ThemeSettingsPage()),
|
||||
),
|
||||
GoRoute(
|
||||
path: Routes.autoSleepTimerSettings.pathName,
|
||||
name: Routes.autoSleepTimerSettings.name,
|
||||
pageBuilder: defaultPageBuilder(
|
||||
const AutoSleepTimerSettingsPage(),
|
||||
),
|
||||
),
|
||||
GoRoute(
|
||||
path: Routes.notificationSettings.pathName,
|
||||
name: Routes.notificationSettings.name,
|
||||
pageBuilder: defaultPageBuilder(
|
||||
const NotificationSettingsPage(),
|
||||
),
|
||||
),
|
||||
GoRoute(
|
||||
path: Routes.playerSettings.pathName,
|
||||
name: Routes.playerSettings.name,
|
||||
pageBuilder: defaultPageBuilder(const PlayerSettingsPage()),
|
||||
),
|
||||
GoRoute(
|
||||
path: Routes.shakeDetectorSettings.pathName,
|
||||
name: Routes.shakeDetectorSettings.name,
|
||||
pageBuilder: defaultPageBuilder(
|
||||
const ShakeDetectorSettingsPage(),
|
||||
),
|
||||
),
|
||||
GoRoute(
|
||||
path: Routes.homePageSettings.pathName,
|
||||
name: Routes.homePageSettings.name,
|
||||
pageBuilder: defaultPageBuilder(
|
||||
const HomePageSettingsPage(),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
GoRoute(
|
||||
path: Routes.userManagement.localPath,
|
||||
name: Routes.userManagement.name,
|
||||
// builder: (context, state) => const UserManagementPage(),
|
||||
pageBuilder: defaultPageBuilder(const ServerManagerPage()),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
),
|
||||
|
||||
Page handleCallback(
|
||||
BuildContext context,
|
||||
GoRouterState state,
|
||||
) {
|
||||
// loggers page
|
||||
GoRoute(
|
||||
path: Routes.logs.localPath,
|
||||
name: Routes.logs.name,
|
||||
// builder: (context, state) => const LogsPage(),
|
||||
pageBuilder: defaultPageBuilder(const LogsPage()),
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
Page handleCallback(BuildContext context, GoRouterState state) {
|
||||
// extract the code and state from the uri
|
||||
final code = state.uri.queryParameters['code'];
|
||||
final stateParam = state.uri.queryParameters['state'];
|
||||
appLogger.fine('deep linking callback: code: $code, state: $stateParam');
|
||||
|
||||
var callbackPage =
|
||||
CallbackPage(code: code, state: stateParam, key: ValueKey(stateParam));
|
||||
var callbackPage = CallbackPage(
|
||||
code: code,
|
||||
state: stateParam,
|
||||
key: ValueKey(stateParam),
|
||||
);
|
||||
return buildPageWithDefaultTransition(
|
||||
context: context,
|
||||
state: state,
|
||||
|
|
|
|||
|
|
@ -23,10 +23,8 @@ const bottomBarHeight = 64;
|
|||
/// BottomNavigationBar, where [child] is placed in the body of the Scaffold.
|
||||
class ScaffoldWithNavBar extends HookConsumerWidget {
|
||||
/// Constructs an [ScaffoldWithNavBar].
|
||||
const ScaffoldWithNavBar({
|
||||
required this.navigationShell,
|
||||
Key? key,
|
||||
}) : super(key: key ?? const ValueKey<String>('ScaffoldWithNavBar'));
|
||||
const ScaffoldWithNavBar({required this.navigationShell, Key? key})
|
||||
: super(key: key ?? const ValueKey<String>('ScaffoldWithNavBar'));
|
||||
|
||||
/// The navigation shell and container for the branch Navigators.
|
||||
final StatefulNavigationShell navigationShell;
|
||||
|
|
@ -35,10 +33,11 @@ class ScaffoldWithNavBar extends HookConsumerWidget {
|
|||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
// playerExpandProgress is used to animate bottom navigation bar to opacity 0 and slide down when player is expanded
|
||||
// final playerProgress =
|
||||
// useValueListenable(ref.watch(playerExpandProgressNotifierProvider));
|
||||
// useValueListenable(ref.watch(playerExpandProgressProvider));
|
||||
final playerProgress = ref.watch(playerHeightProvider);
|
||||
final playerMaxHeight = MediaQuery.of(context).size.height;
|
||||
var percentExpandedMiniPlayer = (playerProgress - playerMinHeight) /
|
||||
var percentExpandedMiniPlayer =
|
||||
(playerProgress - playerMinHeight) /
|
||||
(playerMaxHeight - playerMinHeight);
|
||||
// Clamp the value between 0 and 1
|
||||
percentExpandedMiniPlayer = percentExpandedMiniPlayer.clamp(0.0, 1.0);
|
||||
|
|
@ -52,9 +51,7 @@ class ScaffoldWithNavBar extends HookConsumerWidget {
|
|||
|
||||
// close miniplayer if it is open
|
||||
if (isPlayerExpanded && pendingPlayerModals == 0) {
|
||||
appLogger.fine(
|
||||
'BackButtonListener: closing the player',
|
||||
);
|
||||
appLogger.fine('BackButtonListener: closing the player');
|
||||
audioBookMiniplayerController.animateToHeight(state: PanelState.MIN);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -96,12 +93,7 @@ class ScaffoldWithNavBar extends HookConsumerWidget {
|
|||
return BackButtonListener(
|
||||
onBackButtonPressed: onBackButtonPressed,
|
||||
child: Scaffold(
|
||||
body: Stack(
|
||||
children: [
|
||||
navigationShell,
|
||||
const AudiobookPlayer(),
|
||||
],
|
||||
),
|
||||
body: Stack(children: [navigationShell, const AudiobookPlayer()]),
|
||||
bottomNavigationBar: Opacity(
|
||||
// Opacity is interpolated from 1 to 0 when player is expanded
|
||||
opacity: 1 - percentExpandedMiniPlayer,
|
||||
|
|
@ -116,11 +108,8 @@ class ScaffoldWithNavBar extends HookConsumerWidget {
|
|||
// `navigationShell.route.branches`.
|
||||
destinations: _navigationItems.map((item) {
|
||||
final isDestinationLibrary = item.name == 'Library';
|
||||
var currentLibrary =
|
||||
ref.watch(currentLibraryProvider).valueOrNull;
|
||||
final libraryIcon = AbsIcons.getIconByName(
|
||||
currentLibrary?.icon,
|
||||
);
|
||||
var currentLibrary = ref.watch(currentLibraryProvider).value;
|
||||
final libraryIcon = AbsIcons.getIconByName(currentLibrary?.icon);
|
||||
final destinationWidget = NavigationDestination(
|
||||
icon: Icon(
|
||||
isDestinationLibrary ? libraryIcon ?? item.icon : item.icon,
|
||||
|
|
|
|||
|
|
@ -33,29 +33,26 @@ CustomTransitionPage buildPageWithDefaultTransition<T>({
|
|||
child: child,
|
||||
transitionsBuilder: (context, animation, secondaryAnimation, child) =>
|
||||
FadeTransition(
|
||||
opacity: animation,
|
||||
child: SlideTransition(
|
||||
position: animation.drive(
|
||||
Tween(
|
||||
begin: const Offset(0, 1.50),
|
||||
end: Offset.zero,
|
||||
).chain(
|
||||
CurveTween(curve: Curves.easeOut),
|
||||
opacity: animation,
|
||||
child: SlideTransition(
|
||||
position: animation.drive(
|
||||
Tween(
|
||||
begin: const Offset(0, 1.50),
|
||||
end: Offset.zero,
|
||||
).chain(CurveTween(curve: Curves.easeOut)),
|
||||
),
|
||||
child: child,
|
||||
),
|
||||
),
|
||||
child: child,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Page<dynamic> Function(BuildContext, GoRouterState) defaultPageBuilder<T>(
|
||||
Widget child,
|
||||
) =>
|
||||
(BuildContext context, GoRouterState state) {
|
||||
return buildPageWithDefaultTransition<T>(
|
||||
context: context,
|
||||
state: state,
|
||||
child: child,
|
||||
);
|
||||
};
|
||||
) => (BuildContext context, GoRouterState state) {
|
||||
return buildPageWithDefaultTransition<T>(
|
||||
context: context,
|
||||
state: state,
|
||||
child: child,
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ class ApiSettings extends _$ApiSettings {
|
|||
@override
|
||||
model.ApiSettings build() {
|
||||
state = readFromBoxOrCreate();
|
||||
ref.listenSelf((_, __) {
|
||||
listenSelf((_, __) {
|
||||
writeToBox();
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -6,20 +6,57 @@ part of 'api_settings_provider.dart';
|
|||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$apiSettingsHash() => r'5bc1e16e9d72b77fb10637aabadf08e8947da580';
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
|
||||
/// See also [ApiSettings].
|
||||
@ProviderFor(ApiSettings)
|
||||
final apiSettingsProvider =
|
||||
NotifierProvider<ApiSettings, model.ApiSettings>.internal(
|
||||
ApiSettings.new,
|
||||
name: r'apiSettingsProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product') ? null : _$apiSettingsHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
final apiSettingsProvider = ApiSettingsProvider._();
|
||||
|
||||
typedef _$ApiSettings = Notifier<model.ApiSettings>;
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package
|
||||
final class ApiSettingsProvider
|
||||
extends $NotifierProvider<ApiSettings, model.ApiSettings> {
|
||||
ApiSettingsProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
retry: null,
|
||||
name: r'apiSettingsProvider',
|
||||
isAutoDispose: false,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$apiSettingsHash();
|
||||
|
||||
@$internal
|
||||
@override
|
||||
ApiSettings create() => ApiSettings();
|
||||
|
||||
/// {@macro riverpod.override_with_value}
|
||||
Override overrideWithValue(model.ApiSettings value) {
|
||||
return $ProviderOverride(
|
||||
origin: this,
|
||||
providerOverride: $SyncValueProvider<model.ApiSettings>(value),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
String _$apiSettingsHash() => r'02af850985338eade33d76fc9965808bed548290';
|
||||
|
||||
abstract class _$ApiSettings extends $Notifier<model.ApiSettings> {
|
||||
model.ApiSettings build();
|
||||
@$mustCallSuper
|
||||
@override
|
||||
void runBuild() {
|
||||
final ref = this.ref as $Ref<model.ApiSettings, model.ApiSettings>;
|
||||
final element =
|
||||
ref.element
|
||||
as $ClassProviderElement<
|
||||
AnyNotifier<model.ApiSettings, model.ApiSettings>,
|
||||
model.ApiSettings,
|
||||
Object?,
|
||||
Object?
|
||||
>;
|
||||
element.handleCreate(ref, build);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,8 +19,10 @@ model.AppSettings loadOrCreateAppSettings() {
|
|||
settings = _box.getAt(0);
|
||||
_logger.fine('found settings in box: $settings');
|
||||
} catch (e) {
|
||||
_logger.warning('error reading settings from box: $e'
|
||||
'\nclearing box');
|
||||
_logger.warning(
|
||||
'error reading settings from box: $e'
|
||||
'\nclearing box',
|
||||
);
|
||||
_box.clear();
|
||||
}
|
||||
} else {
|
||||
|
|
@ -34,7 +36,7 @@ class AppSettings extends _$AppSettings {
|
|||
@override
|
||||
model.AppSettings build() {
|
||||
state = loadOrCreateAppSettings();
|
||||
ref.listenSelf((_, __) {
|
||||
listenSelf((_, __) {
|
||||
writeToBox();
|
||||
});
|
||||
return state;
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue