Compare commits

..

No commits in common. "e23c0b6c5f1cc55f3d75ea96b6b218037e5d6fee" and "07aea41c6e048109d87dff5d1b3b93088ddd64b3" have entirely different histories.

148 changed files with 11113 additions and 9291 deletions

2
.fvmrc
View file

@ -1,3 +1,3 @@
{ {
"flutter": "3.38.6" "flutter": "3.32.0"
} }

View file

@ -22,7 +22,7 @@
"utsname", "utsname",
"Vaani" "Vaani"
], ],
"dart.flutterSdkPath": ".fvm/versions/3.38.6", "dart.flutterSdkPath": ".fvm/versions/3.32.0",
"files.exclude": { "files.exclude": {
"**/*.freezed.dart": true, "**/*.freezed.dart": true,
"**/*.g.dart": true "**/*.g.dart": true

View file

@ -31,10 +31,10 @@ if (keystorePropertiesFile.exists()) {
android { android {
namespace "dr.blank.vaani" namespace "dr.blank.vaani"
compileSdk flutter.compileSdkVersion compileSdk flutter.compileSdkVersion
ndkVersion flutter.ndkVersion // ndkVersion flutter.ndkVersion
// The NDK version is set to a specific version since it was not building // 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 // TODO remove when https://github.com/flutter/flutter/issues/139427 is closed
// ndkVersion = "29.0.13113456" ndkVersion = "29.0.13113456"
compileOptions { compileOptions {
@ -64,7 +64,7 @@ android {
applicationId "dr.blank.vaani" applicationId "dr.blank.vaani"
// You can update the following values to match your application needs. // 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. // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
minSdkVersion flutter.minSdkVersion minSdkVersion 23
targetSdkVersion flutter.targetSdkVersion targetSdkVersion flutter.targetSdkVersion
versionCode flutterVersionCode.toInteger() versionCode flutterVersionCode.toInteger()
versionName flutterVersionName versionName flutterVersionName

View file

@ -20,7 +20,7 @@ pluginManagement {
plugins { plugins {
id "dev.flutter.flutter-plugin-loader" version "1.0.0" id "dev.flutter.flutter-plugin-loader" version "1.0.0"
id "com.android.application" version '8.10.0' apply false id "com.android.application" version '8.10.0' apply false
id "org.jetbrains.kotlin.android" version "2.1.10" apply false id "org.jetbrains.kotlin.android" version "2.0.20" apply false
} }
include ":app" include ":app"

View file

@ -16,8 +16,10 @@ import 'package:vaani/shared/extensions/obfuscation.dart';
part 'api_provider.g.dart'; part 'api_provider.g.dart';
// TODO: workaround for https://github.com/rrousselGit/riverpod/issues/3718 // TODO: workaround for https://github.com/rrousselGit/riverpod/issues/3718
typedef ResponseErrorHandler = typedef ResponseErrorHandler = void Function(
void Function(Response response, [Object? error]); Response response, [
Object? error,
]);
final _logger = Logger('api_provider'); final _logger = Logger('api_provider');
@ -37,7 +39,9 @@ AudiobookshelfApi audiobookshelfApi(Ref ref, Uri? baseUrl) {
// try to get the base url from app settings // try to get the base url from app settings
final apiSettings = ref.watch(apiSettingsProvider); final apiSettings = ref.watch(apiSettingsProvider);
baseUrl ??= apiSettings.activeServer?.serverUrl; baseUrl ??= apiSettings.activeServer?.serverUrl;
return AudiobookshelfApi(baseUrl: makeBaseUrl(baseUrl.toString())); return AudiobookshelfApi(
baseUrl: makeBaseUrl(baseUrl.toString()),
);
} }
/// get the api instance for the authenticated user /// get the api instance for the authenticated user
@ -64,9 +68,9 @@ FutureOr<bool> isServerAlive(Ref ref, String address) async {
} }
try { try {
return await AudiobookshelfApi( return await AudiobookshelfApi(baseUrl: makeBaseUrl(address))
baseUrl: makeBaseUrl(address), .server
).server.ping() ?? .ping() ??
false; false;
} catch (e) { } catch (e) {
return false; return false;
@ -82,9 +86,8 @@ FutureOr<ServerStatusResponse?> serverStatus(
]) async { ]) async {
_logger.fine('fetching server status: ${baseUrl.obfuscate()}'); _logger.fine('fetching server status: ${baseUrl.obfuscate()}');
final api = ref.watch(audiobookshelfApiProvider(baseUrl)); final api = ref.watch(audiobookshelfApiProvider(baseUrl));
final res = await api.server.status( final res =
responseErrorHandler: responseErrorHandler, await api.server.status(responseErrorHandler: responseErrorHandler);
);
_logger.fine('server status: $res'); _logger.fine('server status: $res');
return res; return res;
} }
@ -110,9 +113,7 @@ class PersonalizedView extends _$PersonalizedView {
yield []; yield [];
return; return;
} }
ref ref.read(apiSettingsProvider.notifier).updateState(
.read(apiSettingsProvider.notifier)
.updateState(
apiSettings.copyWith(activeLibraryId: login.userDefaultLibraryId), apiSettings.copyWith(activeLibraryId: login.userDefaultLibraryId),
); );
yield []; yield [];
@ -121,8 +122,9 @@ class PersonalizedView extends _$PersonalizedView {
// try to find in cache // try to find in cache
// final cacheKey = 'personalizedView:${apiSettings.activeLibraryId}'; // final cacheKey = 'personalizedView:${apiSettings.activeLibraryId}';
final key = 'personalizedView:${apiSettings.activeLibraryId! + user.id}'; final key = 'personalizedView:${apiSettings.activeLibraryId! + user.id}';
final cachedRes = final cachedRes = await apiResponseCacheManager.getFileFromMemory(
await apiResponseCacheManager.getFileFromMemory(key) ?? key,
) ??
await apiResponseCacheManager.getFileFromCache(key); await apiResponseCacheManager.getFileFromCache(key);
if (cachedRes != null) { if (cachedRes != null) {
_logger.fine('reading from cache: $cachedRes for key: $key'); _logger.fine('reading from cache: $cachedRes for key: $key');
@ -141,9 +143,8 @@ class PersonalizedView extends _$PersonalizedView {
// ! exaggerated delay // ! exaggerated delay
// await Future.delayed(const Duration(seconds: 2)); // await Future.delayed(const Duration(seconds: 2));
final res = await api.libraries.getPersonalized( final res = await api.libraries
libraryId: apiSettings.activeLibraryId!, .getPersonalized(libraryId: apiSettings.activeLibraryId!);
);
// debugPrint('personalizedView: ${res!.map((e) => e).toSet()}'); // debugPrint('personalizedView: ${res!.map((e) => e).toSet()}');
// save to cache // save to cache
if (res != null) { if (res != null) {
@ -171,7 +172,9 @@ class PersonalizedView extends _$PersonalizedView {
/// fetch continue listening audiobooks /// fetch continue listening audiobooks
@riverpod @riverpod
FutureOr<GetUserSessionsResponse> fetchContinueListening(Ref ref) async { FutureOr<GetUserSessionsResponse> fetchContinueListening(
Ref ref,
) async {
final api = ref.watch(authenticatedApiProvider); final api = ref.watch(authenticatedApiProvider);
final res = await api.me.getSessions(); final res = await api.me.getSessions();
// debugPrint( // debugPrint(
@ -181,7 +184,9 @@ FutureOr<GetUserSessionsResponse> fetchContinueListening(Ref ref) async {
} }
@riverpod @riverpod
FutureOr<User> me(Ref ref) async { FutureOr<User> me(
Ref ref,
) async {
final api = ref.watch(authenticatedApiProvider); final api = ref.watch(authenticatedApiProvider);
final errorResponseHandler = ErrorResponseHandler(); final errorResponseHandler = ErrorResponseHandler();
final res = await api.me.getUser( final res = await api.me.getUser(
@ -197,7 +202,10 @@ FutureOr<User> me(Ref ref) async {
} }
@riverpod @riverpod
FutureOr<LoginResponse?> login(Ref ref, {AuthenticatedUser? user}) async { FutureOr<LoginResponse?> login(
Ref ref, {
AuthenticatedUser? user,
}) async {
if (user == null) { if (user == null) {
// try to get the user from settings // try to get the user from settings
final apiSettings = ref.watch(apiSettingsProvider); final apiSettings = ref.watch(apiSettingsProvider);

File diff suppressed because it is too large Load diff

View file

@ -19,7 +19,7 @@ final _logger = Logger('authenticated_users_provider');
class AuthenticatedUsers extends _$AuthenticatedUsers { class AuthenticatedUsers extends _$AuthenticatedUsers {
@override @override
Set<model.AuthenticatedUser> build() { Set<model.AuthenticatedUser> build() {
listenSelf((_, __) { ref.listenSelf((_, __) {
writeStateToBox(); writeStateToBox();
}); });
// get the app settings // get the app settings
@ -35,7 +35,9 @@ class AuthenticatedUsers extends _$AuthenticatedUsers {
Set<model.AuthenticatedUser> readFromBoxOrCreate() { Set<model.AuthenticatedUser> readFromBoxOrCreate() {
if (_box.isNotEmpty) { if (_box.isNotEmpty) {
final foundData = _box.getRange(0, _box.length); 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(); return foundData.toSet();
} else { } else {
_logger.fine('no settings found in box'); _logger.fine('no settings found in box');
@ -57,9 +59,11 @@ class AuthenticatedUsers extends _$AuthenticatedUsers {
ref.invalidateSelf(); ref.invalidateSelf();
if (setActive) { if (setActive) {
final apiSettings = ref.read(apiSettingsProvider); final apiSettings = ref.read(apiSettingsProvider);
ref ref.read(apiSettingsProvider.notifier).updateState(
.read(apiSettingsProvider.notifier) apiSettings.copyWith(
.updateState(apiSettings.copyWith(activeUser: user)); activeUser: user,
),
);
} }
} }
@ -82,9 +86,11 @@ class AuthenticatedUsers extends _$AuthenticatedUsers {
// replace the active user with the first user in the list // replace the active user with the first user in the list
// or null if there are no users left // or null if there are no users left
final newActiveUser = state.isNotEmpty ? state.first : null; final newActiveUser = state.isNotEmpty ? state.first : null;
ref ref.read(apiSettingsProvider.notifier).updateState(
.read(apiSettingsProvider.notifier) apiSettings.copyWith(
.updateState(apiSettings.copyWith(activeUser: newActiveUser)); activeUser: newActiveUser,
),
);
} }
} }
} }

View file

@ -6,70 +6,25 @@ part of 'authenticated_users_provider.dart';
// RiverpodGenerator // RiverpodGenerator
// ************************************************************************** // **************************************************************************
// 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
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,
);
@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() => String _$authenticatedUsersHash() =>
r'c5e82cc70ffc31a0d315e3db9e07a141c583471e'; r'5fdd472f62fc3b73ff8417cdce9f02e86c33d00f';
/// provides with a set of authenticated users /// 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,
);
abstract class _$AuthenticatedUsers typedef _$AuthenticatedUsers
extends $Notifier<Set<model.AuthenticatedUser>> { = AutoDisposeNotifier<Set<model.AuthenticatedUser>>;
Set<model.AuthenticatedUser> build(); // ignore_for_file: type=lint
@$mustCallSuper // 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
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);
}
}

View file

@ -27,8 +27,7 @@ class CoverImage extends _$CoverImage {
// await Future.delayed(const Duration(seconds: 2)); // await Future.delayed(const Duration(seconds: 2));
// try to get the image from the cache // try to get the image from the cache
final file = final file = await imageCacheManager.getFileFromMemory(itemId) ??
await imageCacheManager.getFileFromMemory(itemId) ??
await imageCacheManager.getFileFromCache(itemId); await imageCacheManager.getFileFromCache(itemId);
if (file != null) { if (file != null) {
@ -45,7 +44,9 @@ class CoverImage extends _$CoverImage {
); );
return; return;
} else { } else {
_logger.fine('cover image stale for $itemId, fetching from the server'); _logger.fine(
'cover image stale for $itemId, fetching from the server',
);
} }
} else { } else {
_logger.fine('cover image not found in cache for $itemId'); _logger.fine('cover image not found in cache for $itemId');

View file

@ -6,94 +6,169 @@ part of 'image_provider.dart';
// RiverpodGenerator // RiverpodGenerator
// ************************************************************************** // **************************************************************************
// GENERATED CODE - DO NOT MODIFY BY HAND String _$coverImageHash() => r'89cc4783cbc76bb41beae34384d92fb277135c75';
// ignore_for_file: type=lint, type=warning
@ProviderFor(CoverImage) /// Copied from Dart SDK
final coverImageProvider = CoverImageFamily._(); class _SystemHash {
_SystemHash._();
final class CoverImageProvider static int combine(int hash, int value) {
extends $StreamNotifierProvider<CoverImage, Uint8List> { // ignore: parameter_assignments
CoverImageProvider._({ hash = 0x1fffffff & (hash + value);
required CoverImageFamily super.from, // ignore: parameter_assignments
required String super.argument, hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
}) : super( return hash ^ (hash >> 6);
retry: null, }
name: r'coverImageProvider',
isAutoDispose: false, static int finish(int hash) {
dependencies: null, // ignore: parameter_assignments
$allTransitiveDependencies: null, hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
); // ignore: parameter_assignments
hash = hash ^ (hash >> 11);
@override return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
String debugGetCreateSourceHash() => _$coverImageHash(); }
}
@override
String toString() { abstract class _$CoverImage extends BuildlessStreamNotifier<Uint8List> {
return r'coverImageProvider' late final String itemId;
''
'($argument)'; Stream<Uint8List> build(
String itemId,
);
}
/// See also [CoverImage].
@ProviderFor(CoverImage)
const coverImageProvider = CoverImageFamily();
/// See also [CoverImage].
class CoverImageFamily extends Family<AsyncValue<Uint8List>> {
/// See also [CoverImage].
const CoverImageFamily();
/// See also [CoverImage].
CoverImageProvider call(
String itemId,
) {
return CoverImageProvider(
itemId,
);
} }
@$internal
@override @override
CoverImage create() => CoverImage(); 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);
}
@override @override
bool operator ==(Object other) { bool operator ==(Object other) {
return other is CoverImageProvider && other.argument == argument; return other is CoverImageProvider && other.itemId == itemId;
} }
@override @override
int get hashCode { int get hashCode {
return argument.hashCode; var hash = _SystemHash.combine(0, runtimeType.hashCode);
hash = _SystemHash.combine(hash, itemId.hashCode);
return _SystemHash.finish(hash);
} }
} }
String _$coverImageHash() => r'89cc4783cbc76bb41beae34384d92fb277135c75'; @Deprecated('Will be removed in 3.0. Use Ref instead')
// ignore: unused_element
final class CoverImageFamily extends $Family mixin CoverImageRef on StreamNotifierProviderRef<Uint8List> {
with /// The parameter `itemId` of this provider.
$ClassFamilyOverride< String get itemId;
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 toString() => r'coverImageProvider';
} }
abstract class _$CoverImage extends $StreamNotifier<Uint8List> { class _CoverImageProviderElement
late final _$args = ref.$arg as String; extends StreamNotifierProviderElement<CoverImage, Uint8List>
String get itemId => _$args; with CoverImageRef {
_CoverImageProviderElement(super.provider);
Stream<Uint8List> build(String itemId);
@$mustCallSuper
@override @override
void runBuild() { String get itemId => (origin as CoverImageProvider).itemId;
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

View file

@ -26,8 +26,7 @@ class LibraryItem extends _$LibraryItem {
// look for the item in the cache // look for the item in the cache
final key = CacheKey.libraryItem(id); final key = CacheKey.libraryItem(id);
final cachedFile = final cachedFile = await apiResponseCacheManager.getFileFromMemory(key) ??
await apiResponseCacheManager.getFileFromMemory(key) ??
await apiResponseCacheManager.getFileFromCache(key); await apiResponseCacheManager.getFileFromCache(key);
if (cachedFile != null) { if (cachedFile != null) {
_logger.fine( _logger.fine(

View file

@ -6,112 +6,184 @@ part of 'library_item_provider.dart';
// RiverpodGenerator // RiverpodGenerator
// ************************************************************************** // **************************************************************************
// GENERATED CODE - DO NOT MODIFY BY HAND String _$libraryItemHash() => r'a3cfa7f912e9498a70b5782899018b6964d6445c';
// ignore_for_file: type=lint, type=warning
/// provides the library item for the given id
@ProviderFor(LibraryItem) /// Copied from Dart SDK
final libraryItemProvider = LibraryItemFamily._(); class _SystemHash {
_SystemHash._();
/// provides the library item for the given id static int combine(int hash, int value) {
final class LibraryItemProvider // ignore: parameter_assignments
extends $StreamNotifierProvider<LibraryItem, shelfsdk.LibraryItemExpanded> { hash = 0x1fffffff & (hash + value);
/// provides the library item for the given id // ignore: parameter_assignments
LibraryItemProvider._({ hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
required LibraryItemFamily super.from, return hash ^ (hash >> 6);
required String super.argument, }
}) : super(
retry: null, static int finish(int hash) {
name: r'libraryItemProvider', // ignore: parameter_assignments
isAutoDispose: false, hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
dependencies: null, // ignore: parameter_assignments
$allTransitiveDependencies: null, hash = hash ^ (hash >> 11);
); return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
}
@override }
String debugGetCreateSourceHash() => _$libraryItemHash();
abstract class _$LibraryItem
@override extends BuildlessStreamNotifier<shelfsdk.LibraryItemExpanded> {
String toString() { late final String id;
return r'libraryItemProvider'
'' Stream<shelfsdk.LibraryItemExpanded> build(
'($argument)'; String id,
);
}
/// provides the library item for the given id
///
/// Copied from [LibraryItem].
@ProviderFor(LibraryItem)
const libraryItemProvider = LibraryItemFamily();
/// provides the library item for the given id
///
/// Copied from [LibraryItem].
class LibraryItemFamily
extends Family<AsyncValue<shelfsdk.LibraryItemExpanded>> {
/// provides the library item for the given id
///
/// Copied from [LibraryItem].
const LibraryItemFamily();
/// provides the library item for the given id
///
/// Copied from [LibraryItem].
LibraryItemProvider call(
String id,
) {
return LibraryItemProvider(
id,
);
} }
@$internal
@override @override
LibraryItem create() => LibraryItem(); 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);
}
@override @override
bool operator ==(Object other) { bool operator ==(Object other) {
return other is LibraryItemProvider && other.argument == argument; return other is LibraryItemProvider && other.id == id;
} }
@override @override
int get hashCode { int get hashCode {
return argument.hashCode; var hash = _SystemHash.combine(0, runtimeType.hashCode);
hash = _SystemHash.combine(hash, id.hashCode);
return _SystemHash.finish(hash);
} }
} }
String _$libraryItemHash() => r'a3cfa7f912e9498a70b5782899018b6964d6445c'; @Deprecated('Will be removed in 3.0. Use Ref instead')
// ignore: unused_element
/// provides the library item for the given id mixin LibraryItemRef
on StreamNotifierProviderRef<shelfsdk.LibraryItemExpanded> {
final class LibraryItemFamily extends $Family /// The parameter `id` of this provider.
with String get id;
$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 toString() => r'libraryItemProvider';
} }
/// provides the library item for the given id class _LibraryItemProviderElement extends StreamNotifierProviderElement<
LibraryItem, shelfsdk.LibraryItemExpanded> with LibraryItemRef {
_LibraryItemProviderElement(super.provider);
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 @override
void runBuild() { String get id => (origin as LibraryItemProvider).id;
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

View file

@ -1,5 +1,4 @@
import 'package:hooks_riverpod/hooks_riverpod.dart' import 'package:hooks_riverpod/hooks_riverpod.dart' show Ref;
show Ref, ProviderListenableSelect;
import 'package:logging/logging.dart' show Logger; import 'package:logging/logging.dart' show Logger;
import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart';
@ -33,9 +32,8 @@ Future<Library?> library(Ref ref, String id) async {
@riverpod @riverpod
Future<Library?> currentLibrary(Ref ref) async { Future<Library?> currentLibrary(Ref ref) async {
final libraryId = ref.watch( final libraryId =
apiSettingsProvider.select((s) => s.activeLibraryId), ref.watch(apiSettingsProvider.select((s) => s.activeLibraryId));
);
if (libraryId == null) { if (libraryId == null) {
_logger.warning('No active library id found'); _logger.warning('No active library id found');
return null; return null;

View file

@ -6,153 +6,187 @@ part of 'library_provider.dart';
// RiverpodGenerator // RiverpodGenerator
// ************************************************************************** // **************************************************************************
// GENERATED CODE - DO NOT MODIFY BY HAND String _$libraryHash() => r'f8a34100acb58f02fa958c71a629577bf815710e';
// ignore_for_file: type=lint, type=warning
@ProviderFor(library) /// Copied from Dart SDK
final libraryProvider = LibraryFamily._(); class _SystemHash {
_SystemHash._();
final class LibraryProvider static int combine(int hash, int value) {
extends // ignore: parameter_assignments
$FunctionalProvider<AsyncValue<Library?>, Library?, FutureOr<Library?>> hash = 0x1fffffff & (hash + value);
with $FutureModifier<Library?>, $FutureProvider<Library?> { // ignore: parameter_assignments
LibraryProvider._({ hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
required LibraryFamily super.from, return hash ^ (hash >> 6);
required String super.argument,
}) : super(
retry: null,
name: r'libraryProvider',
isAutoDispose: true,
dependencies: null,
$allTransitiveDependencies: null,
);
@override
String debugGetCreateSourceHash() => _$libraryHash();
@override
String toString() {
return r'libraryProvider'
''
'($argument)';
} }
@$internal static int finish(int hash) {
@override // ignore: parameter_assignments
$FutureProviderElement<Library?> $createElement($ProviderPointer pointer) => hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
$FutureProviderElement(pointer); // ignore: parameter_assignments
hash = hash ^ (hash >> 11);
return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
}
}
/// See also [library].
@ProviderFor(library)
const libraryProvider = LibraryFamily();
/// See also [library].
class LibraryFamily extends Family<AsyncValue<Library?>> {
/// See also [library].
const LibraryFamily();
/// See also [library].
LibraryProvider call(
String id,
) {
return LibraryProvider(
id,
);
}
@override @override
FutureOr<Library?> create(Ref ref) { LibraryProvider getProviderOverride(
final argument = this.argument as String; covariant LibraryProvider provider,
return library(ref, argument); ) {
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'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);
} }
@override @override
bool operator ==(Object other) { bool operator ==(Object other) {
return other is LibraryProvider && other.argument == argument; return other is LibraryProvider && other.id == id;
} }
@override @override
int get hashCode { int get hashCode {
return argument.hashCode; var hash = _SystemHash.combine(0, runtimeType.hashCode);
hash = _SystemHash.combine(hash, id.hashCode);
return _SystemHash.finish(hash);
} }
} }
String _$libraryHash() => r'f8a34100acb58f02fa958c71a629577bf815710e'; @Deprecated('Will be removed in 3.0. Use Ref instead')
// ignore: unused_element
final class LibraryFamily extends $Family mixin LibraryRef on AutoDisposeFutureProviderRef<Library?> {
with $FunctionalFamilyOverride<FutureOr<Library?>, String> { /// The parameter `id` of this provider.
LibraryFamily._() String get id;
: super(
retry: null,
name: r'libraryProvider',
dependencies: null,
$allTransitiveDependencies: null,
isAutoDispose: true,
);
LibraryProvider call(String id) =>
LibraryProvider._(argument: id, from: this);
@override
String toString() => r'libraryProvider';
} }
@ProviderFor(currentLibrary) class _LibraryProviderElement extends AutoDisposeFutureProviderElement<Library?>
final currentLibraryProvider = CurrentLibraryProvider._(); with LibraryRef {
_LibraryProviderElement(super.provider);
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 @override
String debugGetCreateSourceHash() => _$currentLibraryHash(); String get id => (origin as LibraryProvider).id;
@$internal
@override
$FutureProviderElement<Library?> $createElement($ProviderPointer pointer) =>
$FutureProviderElement(pointer);
@override
FutureOr<Library?> create(Ref ref) {
return currentLibrary(ref);
}
} }
String _$currentLibraryHash() => r'658498a531e04a01e2b3915a3319101285601118'; String _$currentLibraryHash() => r'658498a531e04a01e2b3915a3319101285601118';
@ProviderFor(Libraries) /// See also [currentLibrary].
final librariesProvider = LibrariesProvider._(); @ProviderFor(currentLibrary)
final currentLibraryProvider = AutoDisposeFutureProvider<Library?>.internal(
final class LibrariesProvider currentLibrary,
extends $AsyncNotifierProvider<Libraries, List<Library>> { name: r'currentLibraryProvider',
LibrariesProvider._() debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
: super( ? null
from: null, : _$currentLibraryHash,
argument: null,
retry: null,
name: r'librariesProvider',
isAutoDispose: true,
dependencies: null, dependencies: null,
$allTransitiveDependencies: 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'; String _$librariesHash() => r'95ebd4d1ac0cc2acf7617dc22895eff0ca30600f';
abstract class _$Libraries extends $AsyncNotifier<List<Library>> { /// See also [Libraries].
FutureOr<List<Library>> build(); @ProviderFor(Libraries)
@$mustCallSuper final librariesProvider =
@override AutoDisposeAsyncNotifierProvider<Libraries, List<Library>>.internal(
void runBuild() { Libraries.new,
final ref = this.ref as $Ref<AsyncValue<List<Library>>, List<Library>>; name: r'librariesProvider',
final element = debugGetCreateSourceHash:
ref.element const bool.fromEnvironment('dart.vm.product') ? null : _$librariesHash,
as $ClassProviderElement< dependencies: null,
AnyNotifier<AsyncValue<List<Library>>, List<Library>>, allTransitiveDependencies: null,
AsyncValue<List<Library>>, );
Object?,
Object? typedef _$Libraries = AutoDisposeAsyncNotifier<List<Library>>;
>; // ignore_for_file: type=lint
element.handleCreate(ref, build); // ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package
}
}

View file

@ -28,7 +28,7 @@ class ServerAlreadyExistsException implements Exception {
class AudiobookShelfServer extends _$AudiobookShelfServer { class AudiobookShelfServer extends _$AudiobookShelfServer {
@override @override
Set<model.AudiobookShelfServer> build() { Set<model.AudiobookShelfServer> build() {
listenSelf((_, __) { ref.listenSelf((_, __) {
writeStateToBox(); writeStateToBox();
}); });
// get the app settings // get the app settings
@ -80,9 +80,11 @@ class AudiobookShelfServer extends _$AudiobookShelfServer {
// remove the server from the active server // remove the server from the active server
final apiSettings = ref.read(apiSettingsProvider); final apiSettings = ref.read(apiSettingsProvider);
if (apiSettings.activeServer == server) { if (apiSettings.activeServer == server) {
ref ref.read(apiSettingsProvider.notifier).updateState(
.read(apiSettingsProvider.notifier) apiSettings.copyWith(
.updateState(apiSettings.copyWith(activeServer: null)); activeServer: null,
),
);
} }
// remove the users of this server // remove the users of this server
if (removeUsers) { if (removeUsers) {

View file

@ -6,78 +6,25 @@ part of 'server_provider.dart';
// RiverpodGenerator // RiverpodGenerator
// ************************************************************************** // **************************************************************************
// 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
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,
);
@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() => String _$audiobookShelfServerHash() =>
r'144817dcb3704b80c5b60763167fcf932f00c29c'; r'31a96b431221965cd586aad670a32ca901539e41';
/// provides with a set of servers added by the user /// 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,
);
abstract class _$AudiobookShelfServer typedef _$AudiobookShelfServer
extends $Notifier<Set<model.AudiobookShelfServer>> { = AutoDisposeNotifier<Set<model.AudiobookShelfServer>>;
Set<model.AudiobookShelfServer> build(); // ignore_for_file: type=lint
@$mustCallSuper // 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
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);
}
}

View file

@ -1,5 +1,5 @@
import 'package:flutter/foundation.dart' show immutable; import 'package:flutter/foundation.dart' show immutable;
import 'package:hive_plus_secure/hive_plus_secure.dart'; import 'package:hive/hive.dart';
import 'package:vaani/features/per_book_settings/models/book_settings.dart'; import 'package:vaani/features/per_book_settings/models/book_settings.dart';
import 'package:vaani/settings/models/models.dart'; import 'package:vaani/settings/models/models.dart';
@ -14,17 +14,14 @@ class AvailableHiveBoxes {
static final apiSettingsBox = Hive.box<ApiSettings>(name: 'apiSettings'); static final apiSettingsBox = Hive.box<ApiSettings>(name: 'apiSettings');
/// stores the a list of [AudiobookShelfServer] /// stores the a list of [AudiobookShelfServer]
static final serverBox = Hive.box<AudiobookShelfServer>( static final serverBox =
name: 'audiobookShelfServer', Hive.box<AudiobookShelfServer>(name: 'audiobookShelfServer');
);
/// stores the a list of [AuthenticatedUser] /// stores the a list of [AuthenticatedUser]
static final authenticatedUserBox = Hive.box<AuthenticatedUser>( static final authenticatedUserBox =
name: 'authenticatedUser', Hive.box<AuthenticatedUser>(name: 'authenticatedUser');
);
/// stores the a list of [BookSettings] /// stores the a list of [BookSettings]
static final individualBookSettingsBox = Hive.box<BookSettings>( static final individualBookSettingsBox =
name: 'bookSettings', Hive.box<BookSettings>(name: 'bookSettings');
);
} }

View file

@ -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 /// Represents a cover image for a library item
// /// ///
// /// stores 2 paths, one is thumbnail and the other is the full size image /// stores 2 paths, one is thumbnail and the other is the full size image
// /// both are optional /// both are optional
// /// also stores last fetched date for the image /// also stores last fetched date for the image
// /// Id is passed as a parameter to the collection annotation (the lib_item_id) /// Id is passed as a parameter to the collection annotation (the lib_item_id)
// /// also index the id /// also index the id
// /// This is because the image is a part of the library item and the library item /// This is because the image is a part of the library item and the library item
// /// is the parent of the image /// is the parent of the image
// @Collection(ignore: {'path'}) @Collection(ignore: {'path'})
// @Name('CacheImage') @Name('CacheImage')
// class Image { class Image {
// @Id() @Id()
// int id; int id;
// String? thumbnailPath; String? thumbnailPath;
// String? imagePath; String? imagePath;
// DateTime lastSaved; DateTime lastSaved;
// Image({ Image({
// required this.id, required this.id,
// this.thumbnailPath, this.thumbnailPath,
// this.imagePath, this.imagePath,
// }) : lastSaved = DateTime.now(); }) : lastSaved = DateTime.now();
// /// returns the path to the image /// returns the path to the image
// String? get path => thumbnailPath ?? imagePath; String? get path => thumbnailPath ?? imagePath;
// /// automatically updates the last fetched date when saving a new path /// automatically updates the last fetched date when saving a new path
// void updatePath(String? thumbnailPath, String? imagePath) async { void updatePath(String? thumbnailPath, String? imagePath) async {
// this.thumbnailPath = thumbnailPath; this.thumbnailPath = thumbnailPath;
// this.imagePath = imagePath; this.imagePath = imagePath;
// lastSaved = DateTime.now(); lastSaved = DateTime.now();
// } }
// } }

1009
lib/db/cache/schemas/image.g.dart vendored Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,6 @@
import 'dart:io'; import 'dart:io';
import 'package:hive_plus_secure/hive_plus_secure.dart'; import 'package:hive/hive.dart';
import 'package:path/path.dart' as p; import 'package:path/path.dart' as p;
import 'package:path_provider/path_provider.dart'; import 'package:path_provider/path_provider.dart';
import 'package:vaani/main.dart'; import 'package:vaani/main.dart';
@ -13,7 +13,12 @@ Future initStorage() async {
final dir = await getApplicationDocumentsDirectory(); final dir = await getApplicationDocumentsDirectory();
// use vaani as the directory for hive // 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); await storageDir.create(recursive: true);
Hive.defaultDirectory = storageDir.path; Hive.defaultDirectory = storageDir.path;

View file

@ -1,29 +1,29 @@
// // a table to track preferences of player for each book // a table to track preferences of player for each book
// import 'package:isar/isar.dart'; import 'package:isar/isar.dart';
// part 'book_prefs.g.dart'; part 'book_prefs.g.dart';
// /// stores the preferences of the player for a book /// stores the preferences of the player for a book
// @Collection() @Collection()
// @Name('BookPrefs') @Name('BookPrefs')
// class BookPrefs { class BookPrefs {
// @Id() @Id()
// int libItemId; int libItemId;
// double? speed; double? speed;
// // double? volume; // double? volume;
// // Duration? sleepTimer; // Duration? sleepTimer;
// // bool? showTotalProgress; // bool? showTotalProgress;
// // bool? showChapterProgress; // bool? showChapterProgress;
// // bool? useChapterInfo; // bool? useChapterInfo;
// BookPrefs({ BookPrefs({
// required this.libItemId, required this.libItemId,
// this.speed, this.speed,
// // this.volume, // this.volume,
// // this.sleepTimer, // this.sleepTimer,
// // this.showTotalProgress, // this.showTotalProgress,
// // this.showChapterProgress, // this.showChapterProgress,
// // this.useChapterInfo, // this.useChapterInfo,
// }); });
// } }

View file

@ -0,0 +1,496 @@
// 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);
});
}
}

View file

@ -1,4 +1,4 @@
import 'package:hive_plus_secure/hive_plus_secure.dart'; import 'package:hive/hive.dart';
import 'package:vaani/features/per_book_settings/models/book_settings.dart'; import 'package:vaani/features/per_book_settings/models/book_settings.dart';
import 'package:vaani/settings/models/models.dart'; import 'package:vaani/settings/models/models.dart';

View file

@ -67,13 +67,17 @@ class AudiobookDownloadManager {
late StreamSubscription<TaskUpdate> _updatesSubscription; late StreamSubscription<TaskUpdate> _updatesSubscription;
Future<void> queueAudioBookDownload(LibraryItemExpanded item) async { Future<void> queueAudioBookDownload(
LibraryItemExpanded item,
) async {
_logger.info('queuing download for item: ${item.id}'); _logger.info('queuing download for item: ${item.id}');
// create a download task for each file in the item // create a download task for each file in the item
final directory = await getApplicationSupportDirectory(); final directory = await getApplicationSupportDirectory();
for (final file in item.libraryFiles) { for (final file in item.libraryFiles) {
// check if the file is already downloaded // 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}'); _logger.info('file already downloaded: ${file.metadata.filename}');
continue; continue;
} }
@ -101,7 +105,8 @@ class AudiobookDownloadManager {
Directory directory, Directory directory,
LibraryItemExpanded item, LibraryItemExpanded item,
LibraryFile file, LibraryFile file,
) => '${directory.path}/${item.relPath}/${file.metadata.filename}'; ) =>
'${directory.path}/${item.relPath}/${file.metadata.filename}';
void dispose() { void dispose() {
_updatesSubscription.cancel(); _updatesSubscription.cancel();

View file

@ -52,9 +52,13 @@ class DownloadManager extends _$DownloadManager {
return manager; return manager;
} }
Future<void> queueAudioBookDownload(LibraryItemExpanded item) async { Future<void> queueAudioBookDownload(
LibraryItemExpanded item,
) async {
_logger.fine('queueing download for ${item.id}'); _logger.fine('queueing download for ${item.id}');
await state.queueAudioBookDownload(item); await state.queueAudioBookDownload(
item,
);
} }
Future<void> deleteDownloadedItem(LibraryItemExpanded item) async { Future<void> deleteDownloadedItem(LibraryItemExpanded item) async {
@ -79,16 +83,14 @@ class ItemDownloadProgress extends _$ItemDownloadProgress {
Future<double?> build(String id) async { Future<double?> build(String id) async {
final item = await ref.watch(libraryItemProvider(id).future); final item = await ref.watch(libraryItemProvider(id).future);
final manager = ref.read(downloadManagerProvider); final manager = ref.read(downloadManagerProvider);
manager.taskUpdateStream manager.taskUpdateStream.map((taskUpdate) {
.map((taskUpdate) {
if (taskUpdate is! TaskProgressUpdate) { if (taskUpdate is! TaskProgressUpdate) {
return null; return null;
} }
if (taskUpdate.task.group == id) { if (taskUpdate.task.group == id) {
return taskUpdate; return taskUpdate;
} }
}) }).listen((task) async {
.listen((task) async {
if (task != null) { if (task != null) {
final totalSize = item.totalSize; final totalSize = item.totalSize;
// if total size is 0, return 0 // if total size is 0, return 0
@ -96,9 +98,7 @@ class ItemDownloadProgress extends _$ItemDownloadProgress {
state = const AsyncValue.data(0.0); state = const AsyncValue.data(0.0);
return; return;
} }
final downloadedFiles = await manager.getDownloadedFilesMetadata( final downloadedFiles = await manager.getDownloadedFilesMetadata(item);
item,
);
// calculate total size of downloaded files and total size of item, then divide // calculate total size of downloaded files and total size of item, then divide
// to get percentage // to get percentage
final downloadedSize = downloadedFiles.fold<int>( final downloadedSize = downloadedFiles.fold<int>(
@ -110,7 +110,7 @@ class ItemDownloadProgress extends _$ItemDownloadProgress {
final totalDownloadedSize = downloadedSize + inProgressFileSize; final totalDownloadedSize = downloadedSize + inProgressFileSize;
final progress = totalDownloadedSize / totalSize; final progress = totalDownloadedSize / totalSize;
// if current progress is more than calculated progress, do not update // if current progress is more than calculated progress, do not update
if (progress < (state.value ?? 0.0)) { if (progress < (state.valueOrNull ?? 0.0)) {
return; return;
} }
@ -122,14 +122,19 @@ class ItemDownloadProgress extends _$ItemDownloadProgress {
} }
@riverpod @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); return await FileDownloader().database.allRecords(group: group);
} }
@riverpod @riverpod
class IsItemDownloaded extends _$IsItemDownloaded { class IsItemDownloaded extends _$IsItemDownloaded {
@override @override
FutureOr<bool> build(LibraryItemExpanded item) { FutureOr<bool> build(
LibraryItemExpanded item,
) {
final manager = ref.watch(downloadManagerProvider); final manager = ref.watch(downloadManagerProvider);
return manager.isItemDownloaded(item); return manager.isItemDownloaded(item);
} }

File diff suppressed because it is too large Load diff

View file

@ -11,7 +11,9 @@ class DownloadsPage extends HookConsumerWidget {
final downloadHistory = ref.watch(downloadHistoryProvider()); final downloadHistory = ref.watch(downloadHistoryProvider());
return Scaffold( return Scaffold(
appBar: AppBar(title: const Text('Downloads')), appBar: AppBar(
title: const Text('Downloads'),
),
body: Center( body: Center(
// history of downloads // history of downloads
child: downloadHistory.when( child: downloadHistory.when(

View file

@ -6,64 +6,24 @@ part of 'search_controller.dart';
// RiverpodGenerator // 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() => String _$globalSearchControllerHash() =>
r'd854ace6f2e00a10fc33aba63051375f82ad1b10'; r'd854ace6f2e00a10fc33aba63051375f82ad1b10';
/// The controller for the search bar. /// 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,
);
abstract class _$GlobalSearchController typedef _$GlobalSearchController = Notifier<Raw<SearchController>>;
extends $Notifier<Raw<SearchController>> { // ignore_for_file: type=lint
Raw<SearchController> build(); // 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
@$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);
}
}

View file

@ -6,94 +6,186 @@ part of 'search_result_provider.dart';
// RiverpodGenerator // RiverpodGenerator
// ************************************************************************** // **************************************************************************
// GENERATED CODE - DO NOT MODIFY BY HAND String _$searchResultHash() => r'33785de298ad0d53c9d21e8fec88ba2f22f1363f';
// ignore_for_file: type=lint, type=warning
/// The provider for the search result.
@ProviderFor(searchResult) /// Copied from Dart SDK
final searchResultProvider = SearchResultFamily._(); class _SystemHash {
_SystemHash._();
/// The provider for the search result. static int combine(int hash, int value) {
// ignore: parameter_assignments
final class SearchResultProvider hash = 0x1fffffff & (hash + value);
extends // ignore: parameter_assignments
$FunctionalProvider< hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
AsyncValue<LibrarySearchResponse?>, return hash ^ (hash >> 6);
LibrarySearchResponse?,
FutureOr<LibrarySearchResponse?>
>
with
$FutureModifier<LibrarySearchResponse?>,
$FutureProvider<LibrarySearchResponse?> {
/// The provider for the search result.
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 static int finish(int hash) {
@override // ignore: parameter_assignments
$FutureProviderElement<LibrarySearchResponse?> $createElement( hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
$ProviderPointer pointer, // ignore: parameter_assignments
) => $FutureProviderElement(pointer); hash = hash ^ (hash >> 11);
return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
}
}
/// The provider for the search result.
///
/// Copied from [searchResult].
@ProviderFor(searchResult)
const 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();
/// The provider for the search result.
///
/// Copied from [searchResult].
SearchResultProvider call(
String query, {
int limit = 25,
}) {
return SearchResultProvider(
query,
limit: limit,
);
}
@override @override
FutureOr<LibrarySearchResponse?> create(Ref ref) { SearchResultProvider getProviderOverride(
final argument = this.argument as (String, {int limit}); covariant SearchResultProvider provider,
return searchResult(ref, argument.$1, limit: argument.limit); ) {
return call(
provider.query,
limit: provider.limit,
);
}
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'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);
} }
@override @override
bool operator ==(Object other) { bool operator ==(Object other) {
return other is SearchResultProvider && other.argument == argument; return other is SearchResultProvider &&
other.query == query &&
other.limit == limit;
} }
@override @override
int get hashCode { int get hashCode {
return argument.hashCode; var hash = _SystemHash.combine(0, runtimeType.hashCode);
hash = _SystemHash.combine(hash, query.hashCode);
hash = _SystemHash.combine(hash, limit.hashCode);
return _SystemHash.finish(hash);
} }
} }
String _$searchResultHash() => r'33785de298ad0d53c9d21e8fec88ba2f22f1363f'; @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;
/// The provider for the search result. /// The parameter `limit` of this provider.
int get limit;
}
final class SearchResultFamily extends $Family class _SearchResultProviderElement
with extends AutoDisposeFutureProviderElement<LibrarySearchResponse?>
$FunctionalFamilyOverride< with SearchResultRef {
FutureOr<LibrarySearchResponse?>, _SearchResultProviderElement(super.provider);
(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 @override
String toString() => r'searchResultProvider'; String get query => (origin as SearchResultProvider).query;
@override
int get limit => (origin as SearchResultProvider).limit;
} }
// 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

View file

@ -28,14 +28,18 @@ class ExplorePage extends HookConsumerWidget {
final settings = ref.watch(appSettingsProvider); final settings = ref.watch(appSettingsProvider);
final api = ref.watch(authenticatedApiProvider); final api = ref.watch(authenticatedApiProvider);
return Scaffold( return Scaffold(
appBar: AppBar(title: const Text('Explore')), appBar: AppBar(
title: const Text('Explore'),
),
body: const MySearchBar(), body: const MySearchBar(),
); );
} }
} }
class MySearchBar extends HookConsumerWidget { class MySearchBar extends HookConsumerWidget {
const MySearchBar({super.key}); const MySearchBar({
super.key,
});
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
@ -57,11 +61,8 @@ class MySearchBar extends HookConsumerWidget {
currentQuery = query; currentQuery = query;
// In a real application, there should be some error handling here. // In a real application, there should be some error handling here.
final options = await api.libraries.search( final options = await api.libraries
libraryId: settings.activeLibraryId!, .search(libraryId: settings.activeLibraryId!, query: query, limit: 3);
query: query,
limit: 3,
);
// If another search happened after this one, throw away these options. // If another search happened after this one, throw away these options.
if (currentQuery != query) { if (currentQuery != query) {
@ -96,9 +97,10 @@ class MySearchBar extends HookConsumerWidget {
// opacity: 0.5 for the hint text // opacity: 0.5 for the hint text
hintStyle: WidgetStatePropertyAll( hintStyle: WidgetStatePropertyAll(
Theme.of(context).textTheme.bodyMedium!.copyWith( Theme.of(context).textTheme.bodyMedium!.copyWith(
color: Theme.of( color: Theme.of(context)
context, .colorScheme
).colorScheme.onSurface.withValues(alpha: 0.5), .onSurface
.withValues(alpha: 0.5),
), ),
), ),
textInputAction: TextInputAction.search, textInputAction: TextInputAction.search,
@ -118,7 +120,12 @@ class MySearchBar extends HookConsumerWidget {
); );
}, },
viewOnSubmitted: (value) { viewOnSubmitted: (value) {
context.pushNamed(Routes.search.name, queryParameters: {'q': value}); context.pushNamed(
Routes.search.name,
queryParameters: {
'q': value,
},
);
}, },
suggestionsBuilder: (context, controller) async { suggestionsBuilder: (context, controller) async {
// check if the search controller is empty // check if the search controller is empty
@ -184,12 +191,14 @@ List<Widget> buildBookSearchResult(
SearchResultMiniSection( SearchResultMiniSection(
// title: 'Books', // title: 'Books',
category: SearchResultCategory.books, category: SearchResultCategory.books,
options: options.book.map((result) { options: options.book.map(
(result) {
// convert result to a book object // convert result to a book object
final book = result.libraryItem.media.asBookExpanded; final book = result.libraryItem.media.asBookExpanded;
final metadata = book.metadata.asBookMetadataExpanded; final metadata = book.metadata.asBookMetadataExpanded;
return BookSearchResultMini(book: book, metadata: metadata); return BookSearchResultMini(book: book, metadata: metadata);
}), },
),
), ),
); );
} }
@ -198,9 +207,11 @@ List<Widget> buildBookSearchResult(
SearchResultMiniSection( SearchResultMiniSection(
// title: 'Authors', // title: 'Authors',
category: SearchResultCategory.authors, category: SearchResultCategory.authors,
options: options.authors.map((result) { options: options.authors.map(
(result) {
return ListTile(title: Text(result.name)); return ListTile(title: Text(result.name));
}), },
),
), ),
); );
} }
@ -221,7 +232,7 @@ class BookSearchResultMini extends HookConsumerWidget {
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
final item = ref.watch(libraryItemProvider(book.libraryItemId)).value; final item = ref.watch(libraryItemProvider(book.libraryItemId)).valueOrNull;
final image = item == null final image = item == null
? const AsyncValue.loading() ? const AsyncValue.loading()
: ref.watch(coverImageProvider(item.id)); : ref.watch(coverImageProvider(item.id));
@ -234,7 +245,10 @@ class BookSearchResultMini extends HookConsumerWidget {
child: ClipRRect( child: ClipRRect(
borderRadius: BorderRadius.circular(5), borderRadius: BorderRadius.circular(5),
child: image.when( child: image.when(
data: (bytes) => Image.memory(bytes, fit: BoxFit.cover), data: (bytes) => Image.memory(
bytes,
fit: BoxFit.cover,
),
loading: () => const BookCoverSkeleton(), loading: () => const BookCoverSkeleton(),
error: (error, _) => const Icon(Icons.error), error: (error, _) => const Icon(Icons.error),
), ),
@ -245,7 +259,11 @@ class BookSearchResultMini extends HookConsumerWidget {
subtitle: Text( subtitle: Text(
maxLines: 1, maxLines: 1,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
metadata.authors.map((author) => author.name).join(', '), metadata.authors
.map(
(author) => author.name,
)
.join(', '),
), ),
onTap: () { onTap: () {
// navigate to the book details page // navigate to the book details page

View file

@ -5,7 +5,13 @@ import 'package:vaani/features/explore/providers/search_result_provider.dart';
import 'package:vaani/features/explore/view/explore_page.dart'; import 'package:vaani/features/explore/view/explore_page.dart';
import 'package:vaani/shared/extensions/model_conversions.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 { class SearchResultPage extends HookConsumerWidget {
const SearchResultPage({ const SearchResultPage({
@ -35,7 +41,9 @@ class SearchResultPage extends HookConsumerWidget {
body: results.when( body: results.when(
data: (options) { data: (options) {
if (options == null) { if (options == null) {
return Container(child: const Text('No data found')); return Container(
child: const Text('No data found'),
);
} }
if (options is BookLibrarySearchResponse) { if (options is BookLibrarySearchResponse) {
if (category == null) { if (category == null) {
@ -49,7 +57,10 @@ class SearchResultPage extends HookConsumerWidget {
options.book[index].libraryItem.media.asBookExpanded; options.book[index].libraryItem.media.asBookExpanded;
final metadata = book.metadata.asBookMetadataExpanded; final metadata = book.metadata.asBookMetadataExpanded;
return BookSearchResultMini(book: book, metadata: metadata); return BookSearchResultMini(
book: book,
metadata: metadata,
);
}, },
), ),
SearchResultCategory.authors => Container(), SearchResultCategory.authors => Container(),
@ -60,8 +71,12 @@ class SearchResultPage extends HookConsumerWidget {
} }
return null; return null;
}, },
loading: () => const Center(child: CircularProgressIndicator()), loading: () => const Center(
error: (error, stackTrace) => Center(child: Text('Error: $error')), child: CircularProgressIndicator(),
),
error: (error, stackTrace) => Center(
child: Text('Error: $error'),
),
), ),
); );
} }

View file

@ -26,13 +26,16 @@ import 'package:vaani/shared/extensions/model_conversions.dart';
import 'package:vaani/shared/utils.dart'; import 'package:vaani/shared/utils.dart';
class LibraryItemActions extends HookConsumerWidget { class LibraryItemActions extends HookConsumerWidget {
const LibraryItemActions({super.key, required this.id}); const LibraryItemActions({
super.key,
required this.id,
});
final String id; final String id;
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
final item = ref.watch(libraryItemProvider(id)).value; final item = ref.watch(libraryItemProvider(id)).valueOrNull;
if (item == null) { if (item == null) {
return const SizedBox.shrink(); return const SizedBox.shrink();
} }
@ -65,7 +68,9 @@ class LibraryItemActions extends HookConsumerWidget {
// read list button // read list button
IconButton( IconButton(
onPressed: () {}, onPressed: () {},
icon: const Icon(Icons.playlist_add_rounded), icon: const Icon(
Icons.playlist_add_rounded,
),
), ),
// share button // share button
IconButton( IconButton(
@ -74,9 +79,8 @@ class LibraryItemActions extends HookConsumerWidget {
var currentServerUrl = var currentServerUrl =
apiSettings.activeServer!.serverUrl; apiSettings.activeServer!.serverUrl;
if (!currentServerUrl.hasScheme) { if (!currentServerUrl.hasScheme) {
currentServerUrl = Uri.https( currentServerUrl =
currentServerUrl.toString(), Uri.https(currentServerUrl.toString());
);
} }
handleLaunchUrl( handleLaunchUrl(
Uri.parse( Uri.parse(
@ -136,8 +140,7 @@ class LibraryItemActions extends HookConsumerWidget {
.database .database
.deleteRecordWithId( .deleteRecordWithId(
record record
.task .task.taskId,
.taskId,
); );
Navigator.pop(context); Navigator.pop(context);
}, },
@ -179,13 +182,16 @@ class LibraryItemActions extends HookConsumerWidget {
loading: () => const Center( loading: () => const Center(
child: CircularProgressIndicator(), child: CircularProgressIndicator(),
), ),
error: (error, stackTrace) => error: (error, stackTrace) => Center(
Center(child: Text('Error: $error')), child: Text('Error: $error'),
),
); );
}, },
); );
}, },
icon: const Icon(Icons.more_vert_rounded), icon: const Icon(
Icons.more_vert_rounded,
),
), ),
], ],
), ),
@ -200,20 +206,25 @@ class LibraryItemActions extends HookConsumerWidget {
} }
class LibItemDownloadButton extends HookConsumerWidget { class LibItemDownloadButton extends HookConsumerWidget {
const LibItemDownloadButton({super.key, required this.item}); const LibItemDownloadButton({
super.key,
required this.item,
});
final shelfsdk.LibraryItemExpanded item; final shelfsdk.LibraryItemExpanded item;
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
final isItemDownloaded = ref.watch(isItemDownloadedProvider(item)); final isItemDownloaded = ref.watch(isItemDownloadedProvider(item));
if (isItemDownloaded.value ?? false) { if (isItemDownloaded.valueOrNull ?? false) {
return AlreadyItemDownloadedButton(item: item); return AlreadyItemDownloadedButton(item: item);
} }
final isItemDownloading = ref.watch(isItemDownloadingProvider(item.id)); final isItemDownloading = ref.watch(isItemDownloadingProvider(item.id));
return isItemDownloading return isItemDownloading
? ItemCurrentlyInDownloadQueue(item: item) ? ItemCurrentlyInDownloadQueue(
item: item,
)
: IconButton( : IconButton(
onPressed: () { onPressed: () {
appLogger.fine('Pressed download button'); appLogger.fine('Pressed download button');
@ -222,13 +233,18 @@ class LibItemDownloadButton extends HookConsumerWidget {
.read(downloadManagerProvider.notifier) .read(downloadManagerProvider.notifier)
.queueAudioBookDownload(item); .queueAudioBookDownload(item);
}, },
icon: const Icon(Icons.download_rounded), icon: const Icon(
Icons.download_rounded,
),
); );
} }
} }
class ItemCurrentlyInDownloadQueue extends HookConsumerWidget { class ItemCurrentlyInDownloadQueue extends HookConsumerWidget {
const ItemCurrentlyInDownloadQueue({super.key, required this.item}); const ItemCurrentlyInDownloadQueue({
super.key,
required this.item,
});
final shelfsdk.LibraryItemExpanded item; final shelfsdk.LibraryItemExpanded item;
@ -236,7 +252,7 @@ class ItemCurrentlyInDownloadQueue extends HookConsumerWidget {
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
final progress = ref final progress = ref
.watch(itemDownloadProgressProvider(item.id)) .watch(itemDownloadProgressProvider(item.id))
.value .valueOrNull
?.clamp(0.05, 1.0); ?.clamp(0.05, 1.0);
if (progress == 1) { if (progress == 1) {
@ -247,12 +263,17 @@ class ItemCurrentlyInDownloadQueue extends HookConsumerWidget {
return Stack( return Stack(
alignment: Alignment.center, alignment: Alignment.center,
children: [ children: [
CircularProgressIndicator(value: progress, strokeWidth: 2), CircularProgressIndicator(
value: progress,
strokeWidth: 2,
),
const Icon( const Icon(
Icons.download, Icons.download,
// color: Theme.of(context).progressIndicatorTheme.color, // color: Theme.of(context).progressIndicatorTheme.color,
) )
.animate(onPlay: (controller) => controller.repeat()) .animate(
onPlay: (controller) => controller.repeat(),
)
.fade( .fade(
duration: shimmerDuration, duration: shimmerDuration,
end: 1, end: 1,
@ -271,7 +292,10 @@ class ItemCurrentlyInDownloadQueue extends HookConsumerWidget {
} }
class AlreadyItemDownloadedButton extends HookConsumerWidget { class AlreadyItemDownloadedButton extends HookConsumerWidget {
const AlreadyItemDownloadedButton({super.key, required this.item}); const AlreadyItemDownloadedButton({
super.key,
required this.item,
});
final shelfsdk.LibraryItemExpanded item; final shelfsdk.LibraryItemExpanded item;
@ -293,18 +317,25 @@ class AlreadyItemDownloadedButton extends HookConsumerWidget {
top: 8.0, top: 8.0,
bottom: (isBookPlaying ? playerMinHeight : 0) + 8, 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 { class DownloadSheet extends HookConsumerWidget {
const DownloadSheet({super.key, required this.item}); const DownloadSheet({
super.key,
required this.item,
});
final shelfsdk.LibraryItemExpanded item; final shelfsdk.LibraryItemExpanded item;
@ -336,7 +367,9 @@ class DownloadSheet extends HookConsumerWidget {
// ), // ),
ListTile( ListTile(
title: const Text('Delete'), title: const Text('Delete'),
leading: const Icon(Icons.delete_rounded), leading: const Icon(
Icons.delete_rounded,
),
onTap: () async { onTap: () async {
// show the delete dialog // show the delete dialog
final wasDeleted = await showDialog<bool>( final wasDeleted = await showDialog<bool>(
@ -354,7 +387,9 @@ class DownloadSheet extends HookConsumerWidget {
// delete the file // delete the file
ref ref
.read(downloadManagerProvider.notifier) .read(downloadManagerProvider.notifier)
.deleteDownloadedItem(item); .deleteDownloadedItem(
item,
);
GoRouter.of(context).pop(true); GoRouter.of(context).pop(true);
}, },
child: const Text('Yes'), child: const Text('Yes'),
@ -374,7 +409,11 @@ class DownloadSheet extends HookConsumerWidget {
appLogger.fine('Deleted ${item.media.metadata.title}'); appLogger.fine('Deleted ${item.media.metadata.title}');
GoRouter.of(context).pop(); GoRouter.of(context).pop();
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Deleted ${item.media.metadata.title}')), SnackBar(
content: Text(
'Deleted ${item.media.metadata.title}',
),
),
); );
} }
}, },
@ -385,7 +424,9 @@ class DownloadSheet extends HookConsumerWidget {
} }
class _LibraryItemPlayButton extends HookConsumerWidget { class _LibraryItemPlayButton extends HookConsumerWidget {
const _LibraryItemPlayButton({required this.item}); const _LibraryItemPlayButton({
required this.item,
});
final shelfsdk.LibraryItemExpanded item; final shelfsdk.LibraryItemExpanded item;
@ -436,7 +477,9 @@ class _LibraryItemPlayButton extends HookConsumerWidget {
), ),
label: Text(getPlayDisplayText()), label: Text(getPlayDisplayText()),
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(4)), shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(4),
),
), ),
); );
} }
@ -486,9 +529,8 @@ Future<void> libraryItemPlayButtonOnPressed({
appLogger.info('Setting the book ${book.libraryItemId}'); appLogger.info('Setting the book ${book.libraryItemId}');
appLogger.info('Initial position: ${userMediaProgress?.currentTime}'); appLogger.info('Initial position: ${userMediaProgress?.currentTime}');
final downloadManager = ref.watch(simpleDownloadManagerProvider); final downloadManager = ref.watch(simpleDownloadManagerProvider);
final libItem = await ref.read( final libItem =
libraryItemProvider(book.libraryItemId).future, await ref.read(libraryItemProvider(book.libraryItemId).future);
);
final downloadedUris = await downloadManager.getDownloadedFilesUri(libItem); final downloadedUris = await downloadManager.getDownloadedFilesUri(libItem);
setSourceFuture = player.setSourceAudiobook( setSourceFuture = player.setSourceAudiobook(
book, book,
@ -504,9 +546,8 @@ Future<void> libraryItemPlayButtonOnPressed({
} }
} }
// set the volume as this is the first time playing and dismissing causes the volume to go to 0 // set the volume as this is the first time playing and dismissing causes the volume to go to 0
var bookPlayerSettings = ref var bookPlayerSettings =
.read(bookSettingsProvider(book.libraryItemId)) ref.read(bookSettingsProvider(book.libraryItemId)).playerSettings;
.playerSettings;
var appPlayerSettings = ref.read(appSettingsProvider).playerSettings; var appPlayerSettings = ref.read(appSettingsProvider).playerSettings;
var configurePlayerForEveryBook = var configurePlayerForEveryBook =

View file

@ -42,13 +42,14 @@ class LibraryItemHeroSection extends HookConsumerWidget {
child: Column( child: Column(
children: [ children: [
Hero( Hero(
tag: tag: HeroTagPrefixes.bookCover +
HeroTagPrefixes.bookCover +
itemId + itemId +
(extraMap?.heroTagSuffix ?? ''), (extraMap?.heroTagSuffix ?? ''),
child: ClipRRect( child: ClipRRect(
borderRadius: BorderRadius.circular(16), borderRadius: BorderRadius.circular(16),
child: _BookCover(itemId: itemId), child: _BookCover(
itemId: itemId,
),
), ),
), ),
// a progress bar // a progress bar
@ -58,7 +59,9 @@ class LibraryItemHeroSection extends HookConsumerWidget {
right: 8.0, right: 8.0,
left: 8.0, left: 8.0,
), ),
child: _LibraryItemProgressIndicator(id: itemId), child: _LibraryItemProgressIndicator(
id: itemId,
),
), ),
], ],
), ),
@ -74,7 +77,10 @@ class LibraryItemHeroSection extends HookConsumerWidget {
} }
class _BookDetails extends HookConsumerWidget { class _BookDetails extends HookConsumerWidget {
const _BookDetails({required this.id, this.extraMap}); const _BookDetails({
required this.id,
this.extraMap,
});
final String id; final String id;
final LibraryItemExtras? extraMap; final LibraryItemExtras? extraMap;
@ -84,7 +90,7 @@ class _BookDetails extends HookConsumerWidget {
final itemFromApi = ref.watch(libraryItemProvider(id)); final itemFromApi = ref.watch(libraryItemProvider(id));
final itemBookMetadata = final itemBookMetadata =
itemFromApi.value?.media.metadata.asBookMetadataExpanded; itemFromApi.valueOrNull?.media.metadata.asBookMetadataExpanded;
return Expanded( return Expanded(
child: Padding( child: Padding(
@ -93,7 +99,10 @@ class _BookDetails extends HookConsumerWidget {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
children: [ children: [
_BookTitle(extraMap: extraMap, itemBookMetadata: itemBookMetadata), _BookTitle(
extraMap: extraMap,
itemBookMetadata: itemBookMetadata,
),
Container( Container(
margin: const EdgeInsets.symmetric(vertical: 16), margin: const EdgeInsets.symmetric(vertical: 16),
child: Column( child: Column(
@ -125,14 +134,16 @@ class _BookDetails extends HookConsumerWidget {
} }
class _LibraryItemProgressIndicator extends HookConsumerWidget { class _LibraryItemProgressIndicator extends HookConsumerWidget {
const _LibraryItemProgressIndicator({required this.id}); const _LibraryItemProgressIndicator({
required this.id,
});
final String id; final String id;
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
final player = ref.watch(audiobookPlayerProvider); final player = ref.watch(audiobookPlayerProvider);
final libraryItem = ref.watch(libraryItemProvider(id)).value; final libraryItem = ref.watch(libraryItemProvider(id)).valueOrNull;
if (libraryItem == null) { if (libraryItem == null) {
return const SizedBox.shrink(); return const SizedBox.shrink();
} }
@ -146,15 +157,13 @@ class _LibraryItemProgressIndicator extends HookConsumerWidget {
Duration remainingTime; Duration remainingTime;
if (player.book?.libraryItemId == libraryItem.id) { if (player.book?.libraryItemId == libraryItem.id) {
// final positionStream = useStream(player.slowPositionStream); // final positionStream = useStream(player.slowPositionStream);
progress = progress = (player.positionInBook).inSeconds /
(player.positionInBook).inSeconds /
libraryItem.media.asBookExpanded.duration.inSeconds; libraryItem.media.asBookExpanded.duration.inSeconds;
remainingTime = remainingTime =
libraryItem.media.asBookExpanded.duration - player.positionInBook; libraryItem.media.asBookExpanded.duration - player.positionInBook;
} else { } else {
progress = mediaProgress?.progress ?? 0; progress = mediaProgress?.progress ?? 0;
remainingTime = remainingTime = (libraryItem.media.asBookExpanded.duration -
(libraryItem.media.asBookExpanded.duration -
mediaProgress!.currentTime); mediaProgress!.currentTime);
} }
@ -181,16 +190,19 @@ class _LibraryItemProgressIndicator extends HookConsumerWidget {
semanticsLabel: 'Book progress', semanticsLabel: 'Book progress',
semanticsValue: '${progressInPercent.toStringAsFixed(2)}%', semanticsValue: '${progressInPercent.toStringAsFixed(2)}%',
), ),
const SizedBox.square(dimension: 4.0), const SizedBox.square(
dimension: 4.0,
),
// time remaining // time remaining
Text( Text(
// only show 2 decimal places // only show 2 decimal places
'${remainingTime.smartBinaryFormat} left', '${remainingTime.smartBinaryFormat} left',
style: Theme.of(context).textTheme.bodySmall?.copyWith( style: Theme.of(context).textTheme.bodySmall?.copyWith(
color: Theme.of( color: Theme.of(context)
context, .colorScheme
).colorScheme.onSurface.withValues(alpha: 0.75), .onSurface
.withValues(alpha: 0.75),
), ),
), ),
], ],
@ -200,7 +212,10 @@ class _LibraryItemProgressIndicator extends HookConsumerWidget {
} }
class _HeroSectionSubLabelWithIcon 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 IconData icon;
final Widget text; final Widget text;
@ -210,10 +225,8 @@ class _HeroSectionSubLabelWithIcon extends HookConsumerWidget {
final themeData = Theme.of(context); final themeData = Theme.of(context);
final useFontAwesome = final useFontAwesome =
icon.runtimeType == FontAwesomeIcons.book.runtimeType; icon.runtimeType == FontAwesomeIcons.book.runtimeType;
final useMaterialThemeOnItemPage = ref final useMaterialThemeOnItemPage =
.watch(appSettingsProvider) ref.watch(appSettingsProvider).themeSettings.useMaterialThemeOnItemPage;
.themeSettings
.useMaterialThemeOnItemPage;
final color = useMaterialThemeOnItemPage final color = useMaterialThemeOnItemPage
? themeData.colorScheme.primary ? themeData.colorScheme.primary
: themeData.colorScheme.onSurface.withValues(alpha: 0.75); : themeData.colorScheme.onSurface.withValues(alpha: 0.75);
@ -224,10 +237,20 @@ class _HeroSectionSubLabelWithIcon extends HookConsumerWidget {
Container( Container(
margin: const EdgeInsets.only(right: 8, top: 2), margin: const EdgeInsets.only(right: 8, top: 2),
child: useFontAwesome child: useFontAwesome
? FaIcon(icon, size: 16, color: color) ? FaIcon(
: Icon(icon, size: 16, color: color), icon,
size: 16,
color: color,
)
: Icon(
icon,
size: 16,
color: color,
),
),
Expanded(
child: text,
), ),
Expanded(child: text),
], ],
), ),
); );
@ -315,7 +338,9 @@ class _BookNarrators extends StatelessWidget {
} }
class _BookCover extends HookConsumerWidget { class _BookCover extends HookConsumerWidget {
const _BookCover({required this.itemId}); const _BookCover({
required this.itemId,
});
final String itemId; final String itemId;
@ -333,12 +358,11 @@ class _BookCover extends HookConsumerWidget {
themeOfLibraryItemProvider( themeOfLibraryItemProvider(
itemId, itemId,
brightness: Theme.of(context).brightness, brightness: Theme.of(context).brightness,
highContrast: highContrast: themeSettings.highContrast ||
themeSettings.highContrast ||
MediaQuery.of(context).highContrast, MediaQuery.of(context).highContrast,
), ),
) )
.value; .valueOrNull;
} }
return ThemeSwitcher( return ThemeSwitcher(
@ -367,10 +391,15 @@ class _BookCover extends HookConsumerWidget {
return const Icon(Icons.error); return const Icon(Icons.error);
} }
return Image.memory(image, fit: BoxFit.cover); return Image.memory(
image,
fit: BoxFit.cover,
);
}, },
loading: () { loading: () {
return const Center(child: BookCoverSkeleton()); return const Center(
child: BookCoverSkeleton(),
);
}, },
error: (error, stack) { error: (error, stack) {
return const Center(child: Icon(Icons.error)); return const Center(child: Icon(Icons.error));
@ -382,7 +411,10 @@ class _BookCover extends HookConsumerWidget {
} }
class _BookTitle extends StatelessWidget { class _BookTitle extends StatelessWidget {
const _BookTitle({required this.extraMap, required this.itemBookMetadata}); const _BookTitle({
required this.extraMap,
required this.itemBookMetadata,
});
final LibraryItemExtras? extraMap; final LibraryItemExtras? extraMap;
final shelfsdk.BookMetadataExpanded? itemBookMetadata; final shelfsdk.BookMetadataExpanded? itemBookMetadata;
@ -394,8 +426,7 @@ class _BookTitle extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Hero( Hero(
tag: tag: HeroTagPrefixes.bookTitle +
HeroTagPrefixes.bookTitle +
// itemId + // itemId +
(extraMap?.heroTagSuffix ?? ''), (extraMap?.heroTagSuffix ?? ''),
child: Text( child: Text(

View file

@ -4,13 +4,16 @@ import 'package:vaani/api/library_item_provider.dart';
import 'package:vaani/shared/extensions/model_conversions.dart'; import 'package:vaani/shared/extensions/model_conversions.dart';
class LibraryItemMetadata extends HookConsumerWidget { class LibraryItemMetadata extends HookConsumerWidget {
const LibraryItemMetadata({super.key, required this.id}); const LibraryItemMetadata({
super.key,
required this.id,
});
final String id; final String id;
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
final item = ref.watch(libraryItemProvider(id)).value; final item = ref.watch(libraryItemProvider(id)).valueOrNull;
/// formats the duration of the book as `10h 30m` /// formats the duration of the book as `10h 30m`
/// ///
@ -69,8 +72,7 @@ class LibraryItemMetadata extends HookConsumerWidget {
), ),
_MetadataItem( _MetadataItem(
title: 'Published', title: 'Published',
value: value: itemBookMetadata?.publishedDate ??
itemBookMetadata?.publishedDate ??
itemBookMetadata?.publishedYear ?? itemBookMetadata?.publishedYear ??
'Unknown', 'Unknown',
), ),
@ -85,18 +87,22 @@ class LibraryItemMetadata extends HookConsumerWidget {
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly, mainAxisAlignment: MainAxisAlignment.spaceEvenly,
// alternate between metadata and vertical divider // alternate between metadata and vertical divider
children: List.generate(children.length * 2 - 1, (index) { children: List.generate(
children.length * 2 - 1,
(index) {
if (index.isEven) { if (index.isEven) {
return children[index ~/ 2]; return children[index ~/ 2];
} }
return VerticalDivider( return VerticalDivider(
indent: 6, indent: 6,
endIndent: 6, endIndent: 6,
color: Theme.of( color: Theme.of(context)
context, .colorScheme
).colorScheme.onSurface.withValues(alpha: 0.6), .onSurface
.withValues(alpha: 0.6),
); );
}), },
),
), ),
), ),
); );
@ -105,7 +111,10 @@ class LibraryItemMetadata extends HookConsumerWidget {
/// key-value pair to display as column /// key-value pair to display as column
class _MetadataItem extends StatelessWidget { 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 title;
final String value; final String value;

View file

@ -16,21 +16,25 @@ import 'library_item_hero_section.dart';
import 'library_item_metadata.dart'; import 'library_item_metadata.dart';
class LibraryItemPage extends HookConsumerWidget { 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 String itemId;
final Object? extra; final Object? extra;
static const double _showFabThreshold = 300.0; static const double _showFabThreshold = 300.0;
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
final additionalItemData = extra is LibraryItemExtras final additionalItemData =
? extra as LibraryItemExtras extra is LibraryItemExtras ? extra as LibraryItemExtras : null;
: null;
final scrollController = useScrollController(); final scrollController = useScrollController();
final showFab = useState(false); final showFab = useState(false);
// Effect to listen to scroll changes and update FAB visibility // Effect to listen to scroll changes and update FAB visibility
useEffect(() { useEffect(
() {
void listener() { void listener() {
if (!scrollController.hasClients) { if (!scrollController.hasClients) {
return; // Ensure controller is attached return; // Ensure controller is attached
@ -52,7 +56,9 @@ class LibraryItemPage extends HookConsumerWidget {
// Cleanup: remove the listener when the widget is disposed // Cleanup: remove the listener when the widget is disposed
return () => scrollController.removeListener(listener); return () => scrollController.removeListener(listener);
}, [scrollController]); // Re-run effect if scrollController changes },
[scrollController],
); // Re-run effect if scrollController changes
// --- FAB Scroll-to-Top Logic --- // --- FAB Scroll-to-Top Logic ---
void scrollToTop() { void scrollToTop() {
@ -76,7 +82,10 @@ class LibraryItemPage extends HookConsumerWidget {
transitionBuilder: (Widget child, Animation<double> animation) { transitionBuilder: (Widget child, Animation<double> animation) {
return ScaleTransition( return ScaleTransition(
scale: animation, scale: animation,
child: FadeTransition(opacity: animation, child: child), child: FadeTransition(
opacity: animation,
child: child,
),
); );
}, },
child: showFab.value child: showFab.value
@ -87,7 +96,9 @@ class LibraryItemPage extends HookConsumerWidget {
tooltip: 'Scroll to top', tooltip: 'Scroll to top',
child: const Icon(Icons.arrow_upward), child: const Icon(Icons.arrow_upward),
) )
: const SizedBox.shrink(key: ValueKey('fab-empty')), : const SizedBox.shrink(
key: ValueKey('fab-empty'),
),
), ),
body: CustomScrollView( body: CustomScrollView(
controller: scrollController, controller: scrollController,
@ -104,11 +115,17 @@ class LibraryItemPage extends HookConsumerWidget {
), ),
), ),
// a horizontal display with dividers of metadata // 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 // 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 // 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 // a padding at the bottom to make sure the last item is not hidden by mini player
const SliverToBoxAdapter(child: MiniPlayerBottomPadding()), const SliverToBoxAdapter(child: MiniPlayerBottomPadding()),
], ],
@ -120,12 +137,15 @@ class LibraryItemPage extends HookConsumerWidget {
} }
class LibraryItemDescription extends HookConsumerWidget { class LibraryItemDescription extends HookConsumerWidget {
const LibraryItemDescription({super.key, required this.id}); const LibraryItemDescription({
super.key,
required this.id,
});
final String id; final String id;
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
final item = ref.watch(libraryItemProvider(id)).value; final item = ref.watch(libraryItemProvider(id)).valueOrNull;
if (item == null) { if (item == null) {
return const SizedBox(); return const SizedBox();
} }
@ -140,21 +160,16 @@ class LibraryItemDescription extends HookConsumerWidget {
double calculateWidth( double calculateWidth(
BuildContext context, BuildContext context,
BoxConstraints constraints, { BoxConstraints constraints, {
/// width ratio of the cover image to the available width /// width ratio of the cover image to the available width
double widthRatio = 0.4, double widthRatio = 0.4,
/// height ratio of the cover image to the available height /// height ratio of the cover image to the available height
double maxHeightToUse = 0.25, double maxHeightToUse = 0.25,
}) { }) {
final availHeight = min( final availHeight =
constraints.maxHeight, min(constraints.maxHeight, MediaQuery.of(context).size.height);
MediaQuery.of(context).size.height, final availWidth =
); min(constraints.maxWidth, MediaQuery.of(context).size.width);
final availWidth = min(
constraints.maxWidth,
MediaQuery.of(context).size.width,
);
// make the width widthRatio of the available width // make the width widthRatio of the available width
var width = availWidth * widthRatio; var width = availWidth * widthRatio;

View file

@ -17,14 +17,14 @@ class LibraryItemSliverAppBar extends HookConsumerWidget {
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
final item = ref.watch(libraryItemProvider(id)).value; final item = ref.watch(libraryItemProvider(id)).valueOrNull;
final showTitle = useState(false); final showTitle = useState(false);
useEffect(() { useEffect(
() {
void listener() { void listener() {
final shouldShow = final shouldShow = scrollController.hasClients &&
scrollController.hasClients &&
scrollController.offset > _showTitleThreshold; scrollController.offset > _showTitleThreshold;
if (showTitle.value != shouldShow) { if (showTitle.value != shouldShow) {
showTitle.value = shouldShow; showTitle.value = shouldShow;
@ -40,7 +40,9 @@ class LibraryItemSliverAppBar extends HookConsumerWidget {
} }
}); });
return () => scrollController.removeListener(listener); return () => scrollController.removeListener(listener);
}, [scrollController]); },
[scrollController],
);
return SliverAppBar( return SliverAppBar(
elevation: 0, elevation: 0,

View file

@ -13,7 +13,7 @@ class LibraryBrowserPage extends HookConsumerWidget {
const LibraryBrowserPage({super.key}); const LibraryBrowserPage({super.key});
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
final currentLibrary = ref.watch(currentLibraryProvider).value; final currentLibrary = ref.watch(currentLibraryProvider).valueOrNull;
// Determine the icon to use, with a fallback // Determine the icon to use, with a fallback
final IconData libraryIconData = final IconData libraryIconData =
@ -41,7 +41,8 @@ class LibraryBrowserPage extends HookConsumerWidget {
title: Text(appBarTitle), title: Text(appBarTitle),
), ),
SliverList( SliverList(
delegate: SliverChildListDelegate([ delegate: SliverChildListDelegate(
[
ListTile( ListTile(
title: const Text('Authors'), title: const Text('Authors'),
leading: const Icon(Icons.person), leading: const Icon(Icons.person),
@ -75,7 +76,8 @@ class LibraryBrowserPage extends HookConsumerWidget {
GoRouter.of(context).pushNamed(Routes.downloads.name); GoRouter.of(context).pushNamed(Routes.downloads.name);
}, },
), ),
]), ],
),
), ),
], ],
), ),

View file

@ -59,10 +59,8 @@ String generateZipFileName() {
} }
Level parseLevel(String level) { Level parseLevel(String level) {
return Level.LEVELS.firstWhere( return Level.LEVELS
(l) => l.name == level, .firstWhere((l) => l.name == level, orElse: () => Level.ALL);
orElse: () => Level.ALL,
);
} }
LogRecord parseLogLine(String line) { LogRecord parseLogLine(String line) {

View file

@ -6,48 +6,20 @@ part of 'logs_provider.dart';
// RiverpodGenerator // 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'; String _$logsHash() => r'aa9d3d56586cba6ddf69615320ea605d071ea5e2';
abstract class _$Logs extends $AsyncNotifier<List<LogRecord>> { /// See also [Logs].
FutureOr<List<LogRecord>> build(); @ProviderFor(Logs)
@$mustCallSuper final logsProvider =
@override AutoDisposeAsyncNotifierProvider<Logs, List<LogRecord>>.internal(
void runBuild() { Logs.new,
final ref = this.ref as $Ref<AsyncValue<List<LogRecord>>, List<LogRecord>>; name: r'logsProvider',
final element = debugGetCreateSourceHash:
ref.element const bool.fromEnvironment('dart.vm.product') ? null : _$logsHash,
as $ClassProviderElement< dependencies: null,
AnyNotifier<AsyncValue<List<LogRecord>>, List<LogRecord>>, allTransitiveDependencies: null,
AsyncValue<List<LogRecord>>, );
Object?,
Object? typedef _$Logs = AutoDisposeAsyncNotifier<List<LogRecord>>;
>; // ignore_for_file: type=lint
element.handleCreate(ref, build); // ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package
}
}

View file

@ -54,9 +54,8 @@ class LogsPage extends HookConsumerWidget {
icon: const Icon(Icons.share), icon: const Icon(Icons.share),
onPressed: () async { onPressed: () async {
appLogger.info('Preparing logs for sharing'); appLogger.info('Preparing logs for sharing');
final zipLogFilePath = await ref final zipLogFilePath =
.read(logsProvider.notifier) await ref.read(logsProvider.notifier).getZipFilePath();
.getZipFilePath();
// submit logs // submit logs
final result = await Share.shareXFiles([XFile(zipLogFilePath)]); final result = await Share.shareXFiles([XFile(zipLogFilePath)]);
@ -170,6 +169,7 @@ class LogsPage extends HookConsumerWidget {
children: [ children: [
// a filter for log levels, loggers, and search // a filter for log levels, loggers, and search
// TODO: implement filters and search // TODO: implement filters and search
Expanded( Expanded(
child: logs.when( child: logs.when(
data: (logRecords) { data: (logRecords) {
@ -243,7 +243,9 @@ class LogRecordTile extends StatelessWidget {
style: const TextStyle(fontStyle: FontStyle.italic), style: const TextStyle(fontStyle: FontStyle.italic),
), ),
const TextSpan(text: '\n\n'), const TextSpan(text: '\n\n'),
TextSpan(text: logRecord.message), TextSpan(
text: logRecord.message,
),
], ],
), ),
), ),

View file

@ -5,7 +5,7 @@ import 'package:freezed_annotation/freezed_annotation.dart';
part 'flow.freezed.dart'; part 'flow.freezed.dart';
@freezed @freezed
sealed class Flow with _$Flow { class Flow with _$Flow {
const factory Flow({ const factory Flow({
required Uri serverUri, required Uri serverUri,
required String state, required String state,

View file

@ -1,5 +1,5 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
// coverage:ignore-file // coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint // 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 // 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,272 +9,241 @@ part of 'flow.dart';
// FreezedGenerator // FreezedGenerator
// ************************************************************************** // **************************************************************************
// dart format off
T _$identity<T>(T value) => value; 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 /// @nodoc
mixin _$Flow { 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;
Uri get serverUri; String get state; String get verifier; Cookie get cookie; bool get isFlowComplete; String? get authToken; /// Create a copy of Flow
/// Create a copy of Flow /// with the given fields replaced by the non-null parameter values.
/// with the given fields replaced by the non-null parameter values. @JsonKey(includeFromJson: false, includeToJson: false)
@JsonKey(includeFromJson: false, includeToJson: false) $FlowCopyWith<Flow> get copyWith => throw _privateConstructorUsedError;
@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 /// @nodoc
abstract mixin class $FlowCopyWith<$Res> { abstract class $FlowCopyWith<$Res> {
factory $FlowCopyWith(Flow value, $Res Function(Flow) _then) = _$FlowCopyWithImpl; factory $FlowCopyWith(Flow value, $Res Function(Flow) then) =
@useResult _$FlowCopyWithImpl<$Res, Flow>;
$Res call({ @useResult
Uri serverUri, String state, String verifier, Cookie cookie, bool isFlowComplete, String? authToken $Res call(
}); {Uri serverUri,
String state,
String verifier,
Cookie cookie,
bool isFlowComplete,
String? authToken});
} }
/// @nodoc /// @nodoc
class _$FlowCopyWithImpl<$Res> class _$FlowCopyWithImpl<$Res, $Val extends Flow>
implements $FlowCopyWith<$Res> { implements $FlowCopyWith<$Res> {
_$FlowCopyWithImpl(this._self, this._then); _$FlowCopyWithImpl(this._value, this._then);
final Flow _self; // ignore: unused_field
final $Res Function(Flow) _then; final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of Flow /// Create a copy of Flow
/// with the given fields replaced by the non-null parameter values. /// 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,}) { @pragma('vm:prefer-inline')
return _then(_self.copyWith( @override
serverUri: null == serverUri ? _self.serverUri : serverUri // ignore: cast_nullable_to_non_nullable $Res call({
as Uri,state: null == state ? _self.state : state // ignore: cast_nullable_to_non_nullable Object? serverUri = null,
as String,verifier: null == verifier ? _self.verifier : verifier // ignore: cast_nullable_to_non_nullable Object? state = null,
as String,cookie: null == cookie ? _self.cookie : cookie // ignore: cast_nullable_to_non_nullable Object? verifier = null,
as Cookie,isFlowComplete: null == isFlowComplete ? _self.isFlowComplete : isFlowComplete // ignore: cast_nullable_to_non_nullable Object? cookie = null,
as bool,authToken: freezed == authToken ? _self.authToken : authToken // ignore: cast_nullable_to_non_nullable Object? isFlowComplete = null,
as String?, 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);
}
}
/// @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 /// @nodoc
class _$FlowImpl implements _Flow {
const _$FlowImpl(
{required this.serverUri,
required this.state,
required this.verifier,
required this.cookie,
this.isFlowComplete = false,
this.authToken});
class _Flow implements Flow { @override
const _Flow({required this.serverUri, required this.state, required this.verifier, required this.cookie, this.isFlowComplete = false, this.authToken}); 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
@override final Uri serverUri; String toString() {
@override final String state;
@override final String verifier;
@override final Cookie cookie;
@override@JsonKey() final bool isFlowComplete;
@override final String? 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
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)'; return 'Flow(serverUri: $serverUri, state: $state, verifier: $verifier, cookie: $cookie, isFlowComplete: $isFlowComplete, authToken: $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));
}
@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);
} }
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;
/// 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;
} }
/// @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

View file

@ -53,10 +53,8 @@ class OauthFlows extends _$OauthFlows {
} }
state = { state = {
...state, ...state,
oauthState: state[oauthState]!.copyWith( oauthState: state[oauthState]!
isFlowComplete: true, .copyWith(isFlowComplete: true, authToken: authToken),
authToken: authToken,
),
}; };
} }
} }

View file

@ -6,167 +6,221 @@ part of 'oauth_provider.dart';
// RiverpodGenerator // RiverpodGenerator
// ************************************************************************** // **************************************************************************
// GENERATED CODE - DO NOT MODIFY BY HAND String _$loginInExchangeForCodeHash() =>
// ignore_for_file: type=lint, type=warning r'bfc3945529048a0f536052fd5579b76457560fcd';
@ProviderFor(OauthFlows) /// Copied from Dart SDK
final oauthFlowsProvider = OauthFlowsProvider._(); class _SystemHash {
_SystemHash._();
final class OauthFlowsProvider static int combine(int hash, int value) {
extends $NotifierProvider<OauthFlows, Map<State, Flow>> { // ignore: parameter_assignments
OauthFlowsProvider._() hash = 0x1fffffff & (hash + value);
: super( // ignore: parameter_assignments
from: null, hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
argument: null, return hash ^ (hash >> 6);
retry: null,
name: r'oauthFlowsProvider',
isAutoDispose: false,
dependencies: null,
$allTransitiveDependencies: null,
);
@override
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'; static int finish(int hash) {
// ignore: parameter_assignments
abstract class _$OauthFlows extends $Notifier<Map<State, Flow>> { hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
Map<State, Flow> build(); // ignore: parameter_assignments
@$mustCallSuper hash = hash ^ (hash >> 11);
@override return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
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 /// the code returned by the server in exchange for the verifier
///
/// Copied from [loginInExchangeForCode].
@ProviderFor(loginInExchangeForCode) @ProviderFor(loginInExchangeForCode)
final loginInExchangeForCodeProvider = LoginInExchangeForCodeFamily._(); const loginInExchangeForCodeProvider = LoginInExchangeForCodeFamily();
/// the code returned by the server in exchange for the verifier /// the code returned by the server in exchange for the verifier
///
final class LoginInExchangeForCodeProvider /// Copied from [loginInExchangeForCode].
extends $FunctionalProvider<AsyncValue<String?>, String?, FutureOr<String?>> class LoginInExchangeForCodeFamily extends Family<AsyncValue<String?>> {
with $FutureModifier<String?>, $FutureProvider<String?> {
/// the code returned by the server in exchange for the verifier /// the code returned by the server in exchange for the verifier
LoginInExchangeForCodeProvider._({ ///
required LoginInExchangeForCodeFamily super.from, /// Copied from [loginInExchangeForCode].
required ({ const LoginInExchangeForCodeFamily();
State oauthState,
Code code, /// the code returned by the server in exchange for the verifier
///
/// Copied from [loginInExchangeForCode].
LoginInExchangeForCodeProvider call({
required String oauthState,
required String code,
ErrorResponseHandler? responseHandler, ErrorResponseHandler? responseHandler,
}) }) {
super.argument, return LoginInExchangeForCodeProvider(
}) : super( oauthState: oauthState,
retry: null, code: code,
name: r'loginInExchangeForCodeProvider', responseHandler: responseHandler,
isAutoDispose: true,
dependencies: null,
$allTransitiveDependencies: null,
); );
@override
String debugGetCreateSourceHash() => _$loginInExchangeForCodeHash();
@override
String toString() {
return r'loginInExchangeForCodeProvider'
''
'$argument';
} }
@$internal
@override @override
$FutureProviderElement<String?> $createElement($ProviderPointer pointer) => LoginInExchangeForCodeProvider getProviderOverride(
$FutureProviderElement(pointer); covariant LoginInExchangeForCodeProvider provider,
) {
return call(
oauthState: provider.oauthState,
code: provider.code,
responseHandler: provider.responseHandler,
);
}
static const Iterable<ProviderOrFamily>? _dependencies = null;
@override @override
FutureOr<String?> create(Ref ref) { Iterable<ProviderOrFamily>? get dependencies => _dependencies;
final argument =
this.argument static const Iterable<ProviderOrFamily>? _allTransitiveDependencies = null;
as ({
State oauthState, @override
Code code, 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, ErrorResponseHandler? responseHandler,
}); }) : this._internal(
return loginInExchangeForCode( (ref) => loginInExchangeForCode(
ref, ref as LoginInExchangeForCodeRef,
oauthState: argument.oauthState, oauthState: oauthState,
code: argument.code, code: code,
responseHandler: argument.responseHandler, 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,
dependencies: null,
allTransitiveDependencies: null,
debugGetCreateSourceHash: null,
oauthState: oauthState,
code: code,
responseHandler: responseHandler,
),
);
}
@override
AutoDisposeFutureProviderElement<String?> createElement() {
return _LoginInExchangeForCodeProviderElement(this);
} }
@override @override
bool operator ==(Object other) { bool operator ==(Object other) {
return other is LoginInExchangeForCodeProvider && return other is LoginInExchangeForCodeProvider &&
other.argument == argument; other.oauthState == oauthState &&
other.code == code &&
other.responseHandler == responseHandler;
} }
@override @override
int get hashCode { int get hashCode {
return argument.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);
} }
} }
String _$loginInExchangeForCodeHash() => @Deprecated('Will be removed in 3.0. Use Ref instead')
r'bfc3945529048a0f536052fd5579b76457560fcd'; // ignore: unused_element
mixin LoginInExchangeForCodeRef on AutoDisposeFutureProviderRef<String?> {
/// The parameter `oauthState` of this provider.
String get oauthState;
/// the code returned by the server in exchange for the verifier /// The parameter `code` of this provider.
String get code;
final class LoginInExchangeForCodeFamily extends $Family /// The parameter `responseHandler` of this provider.
with ErrorResponseHandler? get responseHandler;
$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 class _LoginInExchangeForCodeProviderElement
extends AutoDisposeFutureProviderElement<String?>
LoginInExchangeForCodeProvider call({ with LoginInExchangeForCodeRef {
required State oauthState, _LoginInExchangeForCodeProviderElement(super.provider);
required Code code,
ErrorResponseHandler? responseHandler,
}) => LoginInExchangeForCodeProvider._(
argument: (
oauthState: oauthState,
code: code,
responseHandler: responseHandler,
),
from: this,
);
@override @override
String toString() => r'loginInExchangeForCodeProvider'; 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

View file

@ -27,7 +27,9 @@ class CallbackPage extends HookConsumerWidget {
// check if the state is in the flows // check if the state is in the flows
if (!flows.containsKey(state)) { if (!flows.containsKey(state)) {
return const _SomethingWentWrong(message: 'State not found'); return const _SomethingWentWrong(
message: 'State not found',
);
} }
// get the token // get the token
@ -43,21 +45,26 @@ class CallbackPage extends HookConsumerWidget {
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
Text( Text('Contacting server...\nPlease wait\n\nGot:'
'Contacting server...\nPlease wait\n\nGot:' '\nState: $state\nCode: $code'),
'\nState: $state\nCode: $code',
),
loginAuthToken.when( loginAuthToken.when(
data: (authenticationToken) { data: (authenticationToken) {
if (authenticationToken == null) { if (authenticationToken == null) {
handleServerError(context, serverErrorResponse); handleServerError(
context,
serverErrorResponse,
);
return const BackToLoginButton(); return const BackToLoginButton();
} }
return Text('Token: $authenticationToken'); return Text('Token: $authenticationToken');
}, },
loading: () => const CircularProgressIndicator(), loading: () => const CircularProgressIndicator(),
error: (error, _) { error: (error, _) {
handleServerError(context, serverErrorResponse, e: error); handleServerError(
context,
serverErrorResponse,
e: error,
);
return Column( return Column(
children: [ children: [
Text('Error with OAuth flow: $error'), Text('Error with OAuth flow: $error'),
@ -74,7 +81,9 @@ class CallbackPage extends HookConsumerWidget {
} }
class BackToLoginButton extends StatelessWidget { class BackToLoginButton extends StatelessWidget {
const BackToLoginButton({super.key}); const BackToLoginButton({
super.key,
});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -88,7 +97,9 @@ class BackToLoginButton extends StatelessWidget {
} }
class _SomethingWentWrong 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; final String message;
@ -98,7 +109,10 @@ class _SomethingWentWrong extends StatelessWidget {
body: Center( body: Center(
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [Text(message), const BackToLoginButton()], children: [
Text(message),
const BackToLoginButton(),
],
), ),
), ),
); );

View file

@ -9,7 +9,9 @@ import 'package:vaani/shared/utils.dart';
import 'package:vaani/shared/widgets/add_new_server.dart'; import 'package:vaani/shared/widgets/add_new_server.dart';
class OnboardingSinglePage extends HookConsumerWidget { class OnboardingSinglePage extends HookConsumerWidget {
const OnboardingSinglePage({super.key}); const OnboardingSinglePage({
super.key,
});
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
@ -21,9 +23,8 @@ class OnboardingSinglePage extends HookConsumerWidget {
child: ConstrainedBox( child: ConstrainedBox(
constraints: BoxConstraints( constraints: BoxConstraints(
maxWidth: 600, maxWidth: 600,
minWidth: constraints.maxWidth < 600 minWidth:
? constraints.maxWidth constraints.maxWidth < 600 ? constraints.maxWidth : 0,
: 0,
), ),
child: const Padding( child: const Padding(
padding: EdgeInsets.symmetric(vertical: 20.0), padding: EdgeInsets.symmetric(vertical: 20.0),
@ -38,7 +39,10 @@ class OnboardingSinglePage extends HookConsumerWidget {
} }
} }
Widget fadeSlideTransitionBuilder(Widget child, Animation<double> animation) { Widget fadeSlideTransitionBuilder(
Widget child,
Animation<double> animation,
) {
return FadeTransition( return FadeTransition(
opacity: animation, opacity: animation,
child: SlideTransition( child: SlideTransition(
@ -52,7 +56,9 @@ Widget fadeSlideTransitionBuilder(Widget child, Animation<double> animation) {
} }
class OnboardingBody extends HookConsumerWidget { class OnboardingBody extends HookConsumerWidget {
const OnboardingBody({super.key}); const OnboardingBody({
super.key,
});
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
@ -75,7 +81,9 @@ class OnboardingBody extends HookConsumerWidget {
style: Theme.of(context).textTheme.headlineSmall, style: Theme.of(context).textTheme.headlineSmall,
), ),
), ),
const SizedBox.square(dimension: 16.0), const SizedBox.square(
dimension: 16.0,
),
Padding( Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
child: AnimatedSwitcher( child: AnimatedSwitcher(
@ -104,12 +112,16 @@ class OnboardingBody extends HookConsumerWidget {
}, },
), ),
), ),
const SizedBox.square(dimension: 16.0), const SizedBox.square(
dimension: 16.0,
),
AnimatedSwitcher( AnimatedSwitcher(
duration: 500.ms, duration: 500.ms,
transitionBuilder: fadeSlideTransitionBuilder, transitionBuilder: fadeSlideTransitionBuilder,
child: canUserLogin.value child: canUserLogin.value
? UserLoginWidget(server: audiobookshelfUri) ? UserLoginWidget(
server: audiobookshelfUri,
)
// ).animate().fade(duration: 600.ms).slideY(begin: 0.3, end: 0) // ).animate().fade(duration: 600.ms).slideY(begin: 0.3, end: 0)
: const RedirectToABS().animate().fadeIn().slideY( : const RedirectToABS().animate().fadeIn().slideY(
curve: Curves.easeInOut, curve: Curves.easeInOut,
@ -122,7 +134,9 @@ class OnboardingBody extends HookConsumerWidget {
} }
class RedirectToABS extends StatelessWidget { class RedirectToABS extends StatelessWidget {
const RedirectToABS({super.key}); const RedirectToABS({
super.key,
});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -138,14 +152,18 @@ class RedirectToABS extends StatelessWidget {
isSemanticButton: false, isSemanticButton: false,
style: ButtonStyle( style: ButtonStyle(
elevation: WidgetStateProperty.all(0), elevation: WidgetStateProperty.all(0),
padding: WidgetStateProperty.all(const EdgeInsets.all(0)), padding: WidgetStateProperty.all(
const EdgeInsets.all(0),
),
), ),
onPressed: () async { onPressed: () async {
// open the github page // open the github page
// ignore: avoid_print // ignore: avoid_print
print('Opening the github page'); print('Opening the github page');
await handleLaunchUrl( await handleLaunchUrl(
Uri.parse('https://www.audiobookshelf.org'), Uri.parse(
'https://www.audiobookshelf.org',
),
); );
}, },
child: const Text('Click here'), child: const Text('Click here'),

View file

@ -22,7 +22,11 @@ import 'package:vaani/settings/api_settings_provider.dart'
import 'package:vaani/settings/models/models.dart' as model; import 'package:vaani/settings/models/models.dart' as model;
class UserLoginWidget extends HookConsumerWidget { 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 Uri server;
final Function(model.AuthenticatedUser)? onSuccess; final Function(model.AuthenticatedUser)? onSuccess;
@ -30,9 +34,8 @@ class UserLoginWidget extends HookConsumerWidget {
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
final serverStatusError = useMemoized(() => ErrorResponseHandler(), []); final serverStatusError = useMemoized(() => ErrorResponseHandler(), []);
final serverStatus = ref.watch( final serverStatus =
serverStatusProvider(server, serverStatusError.storeError), ref.watch(serverStatusProvider(server, serverStatusError.storeError));
);
return serverStatus.when( return serverStatus.when(
data: (value) { data: (value) {
@ -52,7 +55,9 @@ class UserLoginWidget extends HookConsumerWidget {
); );
}, },
loading: () { loading: () {
return const Center(child: CircularProgressIndicator()); return const Center(
child: CircularProgressIndicator(),
);
}, },
error: (error, _) { error: (error, _) {
return Center( return Center(
@ -63,7 +68,10 @@ class UserLoginWidget extends HookConsumerWidget {
ElevatedButton( ElevatedButton(
onPressed: () { onPressed: () {
ref.invalidate( ref.invalidate(
serverStatusProvider(server, serverStatusError.storeError), serverStatusProvider(
server,
serverStatusError.storeError,
),
); );
}, },
child: const Text('Try again'), child: const Text('Try again'),
@ -76,7 +84,11 @@ class UserLoginWidget extends HookConsumerWidget {
} }
} }
enum AuthMethodChoice { local, openid, authToken } enum AuthMethodChoice {
local,
openid,
authToken,
}
class UserLoginMultipleAuth extends HookConsumerWidget { class UserLoginMultipleAuth extends HookConsumerWidget {
const UserLoginMultipleAuth({ const UserLoginMultipleAuth({
@ -105,17 +117,21 @@ class UserLoginMultipleAuth extends HookConsumerWidget {
); );
model.AudiobookShelfServer addServer() { model.AudiobookShelfServer addServer() {
var newServer = model.AudiobookShelfServer(serverUrl: server); var newServer = model.AudiobookShelfServer(
serverUrl: server,
);
try { try {
// add the server to the list of servers // add the server to the list of servers
ref.read(audiobookShelfServerProvider.notifier).addServer(newServer); ref.read(audiobookShelfServerProvider.notifier).addServer(
newServer,
);
} on ServerAlreadyExistsException catch (e) { } on ServerAlreadyExistsException catch (e) {
newServer = e.server; newServer = e.server;
} finally { } finally {
ref ref.read(apiSettingsProvider.notifier).updateState(
.read(apiSettingsProvider.notifier) ref.read(apiSettingsProvider).copyWith(
.updateState( activeServer: newServer,
ref.read(apiSettingsProvider).copyWith(activeServer: newServer), ),
); );
} }
return newServer; return newServer;
@ -134,15 +150,12 @@ class UserLoginMultipleAuth extends HookConsumerWidget {
runAlignment: WrapAlignment.center, runAlignment: WrapAlignment.center,
runSpacing: 10, runSpacing: 10,
alignment: WrapAlignment.center, alignment: WrapAlignment.center,
children: children: [
[
// a small label to show the user what to do // a small label to show the user what to do
if (localAvailable) if (localAvailable)
ChoiceChip( ChoiceChip(
label: const Text('Local'), label: const Text('Local'),
selected: selected: methodChoice.value == AuthMethodChoice.local,
methodChoice.value ==
AuthMethodChoice.local,
onSelected: (selected) { onSelected: (selected) {
if (selected) { if (selected) {
methodChoice.value = AuthMethodChoice.local; methodChoice.value = AuthMethodChoice.local;
@ -152,31 +165,27 @@ class UserLoginMultipleAuth extends HookConsumerWidget {
if (openIDAvailable) if (openIDAvailable)
ChoiceChip( ChoiceChip(
label: const Text('OpenID'), label: const Text('OpenID'),
selected: selected: methodChoice.value == AuthMethodChoice.openid,
methodChoice.value ==
AuthMethodChoice.openid,
onSelected: (selected) { onSelected: (selected) {
if (selected) { if (selected) {
methodChoice.value = methodChoice.value = AuthMethodChoice.openid;
AuthMethodChoice.openid;
} }
}, },
), ),
ChoiceChip( ChoiceChip(
label: const Text('Token'), label: const Text('Token'),
selected: selected:
methodChoice.value == methodChoice.value == AuthMethodChoice.authToken,
AuthMethodChoice.authToken,
onSelected: (selected) { onSelected: (selected) {
if (selected) { if (selected) {
methodChoice.value = methodChoice.value = AuthMethodChoice.authToken;
AuthMethodChoice.authToken;
} }
}, },
), ),
] ].animate(interval: 100.ms).fadeIn(
.animate(interval: 100.ms) duration: 150.ms,
.fadeIn(duration: 150.ms, curve: Curves.easeIn), curve: Curves.easeIn,
),
), ),
), ),
Padding( Padding(

View file

@ -54,9 +54,9 @@ class UserLoginWithOpenID extends HookConsumerWidget {
if (openIDLoginEndpoint == null) { if (openIDLoginEndpoint == null) {
if (responseErrorHandler.response.statusCode == 400 && if (responseErrorHandler.response.statusCode == 400 &&
responseErrorHandler.response.body.toLowerCase().contains( responseErrorHandler.response.body
RegExp(r'invalid.*redirect.*uri'), .toLowerCase()
)) { .contains(RegExp(r'invalid.*redirect.*uri'))) {
// show error // show error
handleServerError( handleServerError(
context, context,
@ -97,16 +97,16 @@ class UserLoginWithOpenID extends HookConsumerWidget {
); );
// add the flow to the provider // add the flow to the provider
ref ref.read(oauthFlowsProvider.notifier).addFlow(
.read(oauthFlowsProvider.notifier)
.addFlow(
oauthState, oauthState,
verifier: verifier, verifier: verifier,
serverUri: server, serverUri: server,
cookie: Cookie.fromSetCookieValue(authCookie!), cookie: Cookie.fromSetCookieValue(authCookie!),
); );
await handleLaunchUrl(openIDLoginEndpoint); await handleLaunchUrl(
openIDLoginEndpoint,
);
} }
return Column( return Column(

View file

@ -39,14 +39,17 @@ class UserLoginWithPassword extends HookConsumerWidget {
final api = ref.watch(audiobookshelfApiProvider(server)); final api = ref.watch(audiobookshelfApiProvider(server));
// forward animation when the password visibility changes // forward animation when the password visibility changes
useEffect(() { useEffect(
() {
if (isPasswordVisible.value) { if (isPasswordVisible.value) {
isPasswordVisibleAnimationController.forward(); isPasswordVisibleAnimationController.forward();
} else { } else {
isPasswordVisibleAnimationController.reverse(); isPasswordVisibleAnimationController.reverse();
} }
return null; return null;
}, [isPasswordVisible.value]); },
[isPasswordVisible.value],
);
/// Login to the server and save the user /// Login to the server and save the user
Future<void> loginAndSave() async { Future<void> loginAndSave() async {
@ -106,9 +109,10 @@ class UserLoginWithPassword extends HookConsumerWidget {
decoration: InputDecoration( decoration: InputDecoration(
labelText: 'Username', labelText: 'Username',
labelStyle: TextStyle( labelStyle: TextStyle(
color: Theme.of( color: Theme.of(context)
context, .colorScheme
).colorScheme.onSurface.withValues(alpha: 0.8), .onSurface
.withValues(alpha: 0.8),
), ),
border: const OutlineInputBorder(), border: const OutlineInputBorder(),
), ),
@ -125,16 +129,18 @@ class UserLoginWithPassword extends HookConsumerWidget {
decoration: InputDecoration( decoration: InputDecoration(
labelText: 'Password', labelText: 'Password',
labelStyle: TextStyle( labelStyle: TextStyle(
color: Theme.of( color: Theme.of(context)
context, .colorScheme
).colorScheme.onSurface.withValues(alpha: 0.8), .onSurface
.withValues(alpha: 0.8),
), ),
border: const OutlineInputBorder(), border: const OutlineInputBorder(),
suffixIcon: ColorFiltered( suffixIcon: ColorFiltered(
colorFilter: ColorFilter.mode( colorFilter: ColorFilter.mode(
Theme.of( Theme.of(context)
context, .colorScheme
).colorScheme.primary.withValues(alpha: 0.8), .primary
.withValues(alpha: 0.8),
BlendMode.srcIn, BlendMode.srcIn,
), ),
child: InkWell( child: InkWell(
@ -151,7 +157,9 @@ class UserLoginWithPassword extends HookConsumerWidget {
), ),
), ),
), ),
suffixIconConstraints: const BoxConstraints(maxHeight: 45), suffixIconConstraints: const BoxConstraints(
maxHeight: 45,
),
), ),
), ),
const SizedBox(height: 30), const SizedBox(height: 30),
@ -189,12 +197,10 @@ Future<void> handleServerError(
context: context, context: context,
builder: (context) => AlertDialog( builder: (context) => AlertDialog(
title: const Text('Error'), title: const Text('Error'),
content: SelectableText( content: SelectableText('$title\n'
'$title\n'
'Got response: ${responseErrorHandler.response.body} (${responseErrorHandler.response.statusCode})\n' 'Got response: ${responseErrorHandler.response.body} (${responseErrorHandler.response.statusCode})\n'
'Stacktrace: $e\n\n' 'Stacktrace: $e\n\n'
'$body\n\n', '$body\n\n'),
),
actions: [ actions: [
if (outLink != null) if (outLink != null)
TextButton( TextButton(

View file

@ -89,9 +89,10 @@ class UserLoginWithToken extends HookConsumerWidget {
decoration: InputDecoration( decoration: InputDecoration(
labelText: 'API Token', labelText: 'API Token',
labelStyle: TextStyle( labelStyle: TextStyle(
color: Theme.of( color: Theme.of(context)
context, .colorScheme
).colorScheme.onSurface.withValues(alpha: 0.8), .onSurface
.withValues(alpha: 0.8),
), ),
border: const OutlineInputBorder(), border: const OutlineInputBorder(),
), ),
@ -106,7 +107,10 @@ class UserLoginWithToken extends HookConsumerWidget {
}, },
), ),
const SizedBox(height: 10), const SizedBox(height: 10),
ElevatedButton(onPressed: loginAndSave, child: const Text('Login')), ElevatedButton(
onPressed: loginAndSave,
child: const Text('Login'),
),
], ],
), ),
); );

View file

@ -6,7 +6,7 @@ part 'book_settings.g.dart';
/// per book settings /// per book settings
@freezed @freezed
sealed class BookSettings with _$BookSettings { class BookSettings with _$BookSettings {
const factory BookSettings({ const factory BookSettings({
required String bookId, required String bookId,
@Default(NullablePlayerSettings()) NullablePlayerSettings playerSettings, @Default(NullablePlayerSettings()) NullablePlayerSettings playerSettings,

View file

@ -1,5 +1,5 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
// coverage:ignore-file // coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint // 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 // 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,284 +9,195 @@ part of 'book_settings.dart';
// FreezedGenerator // FreezedGenerator
// ************************************************************************** // **************************************************************************
// dart format off
T _$identity<T>(T value) => value; 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 /// @nodoc
mixin _$BookSettings { mixin _$BookSettings {
String get bookId => throw _privateConstructorUsedError;
String get bookId; NullablePlayerSettings get playerSettings; NullablePlayerSettings get playerSettings =>
/// Create a copy of BookSettings throw _privateConstructorUsedError;
/// 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. /// Serializes this BookSettings to a JSON map.
Map<String, dynamic> toJson(); Map<String, dynamic> toJson() => 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)';
}
/// 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 /// @nodoc
abstract mixin class $BookSettingsCopyWith<$Res> { abstract class $BookSettingsCopyWith<$Res> {
factory $BookSettingsCopyWith(BookSettings value, $Res Function(BookSettings) _then) = _$BookSettingsCopyWithImpl; factory $BookSettingsCopyWith(
@useResult BookSettings value, $Res Function(BookSettings) then) =
$Res call({ _$BookSettingsCopyWithImpl<$Res, BookSettings>;
String bookId, NullablePlayerSettings playerSettings @useResult
}); $Res call({String bookId, NullablePlayerSettings playerSettings});
$NullablePlayerSettingsCopyWith<$Res> get playerSettings;
$NullablePlayerSettingsCopyWith<$Res> get playerSettings;
} }
/// @nodoc /// @nodoc
class _$BookSettingsCopyWithImpl<$Res> class _$BookSettingsCopyWithImpl<$Res, $Val extends BookSettings>
implements $BookSettingsCopyWith<$Res> { implements $BookSettingsCopyWith<$Res> {
_$BookSettingsCopyWithImpl(this._self, this._then); _$BookSettingsCopyWithImpl(this._value, this._then);
final BookSettings _self; // ignore: unused_field
final $Res Function(BookSettings) _then; final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of BookSettings /// Create a copy of BookSettings
/// with the given fields replaced by the non-null parameter values. /// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') @override $Res call({Object? bookId = null,Object? playerSettings = null,}) { @pragma('vm:prefer-inline')
return _then(_self.copyWith( @override
bookId: null == bookId ? _self.bookId : bookId // ignore: cast_nullable_to_non_nullable $Res call({
as String,playerSettings: null == playerSettings ? _self.playerSettings : playerSettings // ignore: cast_nullable_to_non_nullable Object? bookId = null,
as NullablePlayerSettings, Object? playerSettings = null,
)); }) {
} return _then(_value.copyWith(
/// Create a copy of BookSettings bookId: null == bookId
/// with the given fields replaced by the non-null parameter values. ? _value.bookId
@override : bookId // ignore: cast_nullable_to_non_nullable
@pragma('vm:prefer-inline') as String,
$NullablePlayerSettingsCopyWith<$Res> get playerSettings { playerSettings: null == playerSettings
? _value.playerSettings
: playerSettings // ignore: cast_nullable_to_non_nullable
as NullablePlayerSettings,
) as $Val);
}
return $NullablePlayerSettingsCopyWith<$Res>(_self.playerSettings, (value) { /// Create a copy of BookSettings
return _then(_self.copyWith(playerSettings: value)); /// 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);
}); });
} }
} }
/// @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});
/// Adds pattern-matching-related methods to [BookSettings]. @override
extension BookSettingsPatterns on BookSettings { $NullablePlayerSettingsCopyWith<$Res> get playerSettings;
/// 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 /// @nodoc
@JsonSerializable() @JsonSerializable()
class _$BookSettingsImpl implements _BookSettings {
const _$BookSettingsImpl(
{required this.bookId,
this.playerSettings = const NullablePlayerSettings()});
class _BookSettings implements BookSettings { factory _$BookSettingsImpl.fromJson(Map<String, dynamic> json) =>
const _BookSettings({required this.bookId, this.playerSettings = const NullablePlayerSettings()}); _$$BookSettingsImplFromJson(json);
factory _BookSettings.fromJson(Map<String, dynamic> json) => _$BookSettingsFromJson(json);
@override final String bookId; @override
@override@JsonKey() final NullablePlayerSettings playerSettings; final String bookId;
@override
@JsonKey()
final NullablePlayerSettings playerSettings;
/// Create a copy of BookSettings @override
/// with the given fields replaced by the non-null parameter values. String toString() {
@override @JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
_$BookSettingsCopyWith<_BookSettings> get copyWith => __$BookSettingsCopyWithImpl<_BookSettings>(this, _$identity);
@override
Map<String, dynamic> toJson() {
return _$BookSettingsToJson(this, );
}
@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)'; return 'BookSettings(bookId: $bookId, playerSettings: $playerSettings)';
}
@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,
);
}
} }
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;
} }
/// @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

View file

@ -6,17 +6,16 @@ part of 'book_settings.dart';
// JsonSerializableGenerator // JsonSerializableGenerator
// ************************************************************************** // **************************************************************************
_BookSettings _$BookSettingsFromJson(Map<String, dynamic> json) => _$BookSettingsImpl _$$BookSettingsImplFromJson(Map<String, dynamic> json) =>
_BookSettings( _$BookSettingsImpl(
bookId: json['bookId'] as String, bookId: json['bookId'] as String,
playerSettings: json['playerSettings'] == null playerSettings: json['playerSettings'] == null
? const NullablePlayerSettings() ? const NullablePlayerSettings()
: NullablePlayerSettings.fromJson( : NullablePlayerSettings.fromJson(
json['playerSettings'] as Map<String, dynamic>, json['playerSettings'] as Map<String, dynamic>),
),
); );
Map<String, dynamic> _$BookSettingsToJson(_BookSettings instance) => Map<String, dynamic> _$$BookSettingsImplToJson(_$BookSettingsImpl instance) =>
<String, dynamic>{ <String, dynamic>{
'bookId': instance.bookId, 'bookId': instance.bookId,
'playerSettings': instance.playerSettings, 'playerSettings': instance.playerSettings,

View file

@ -5,7 +5,7 @@ part 'nullable_player_settings.freezed.dart';
part 'nullable_player_settings.g.dart'; part 'nullable_player_settings.g.dart';
@freezed @freezed
sealed class NullablePlayerSettings with _$NullablePlayerSettings { class NullablePlayerSettings with _$NullablePlayerSettings {
const factory NullablePlayerSettings({ const factory NullablePlayerSettings({
MinimizedPlayerSettings? miniPlayerSettings, MinimizedPlayerSettings? miniPlayerSettings,
ExpandedPlayerSettings? expandedPlayerSettings, ExpandedPlayerSettings? expandedPlayerSettings,

View file

@ -1,5 +1,5 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
// coverage:ignore-file // coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint // 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 // 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,361 +9,369 @@ part of 'nullable_player_settings.dart';
// FreezedGenerator // FreezedGenerator
// ************************************************************************** // **************************************************************************
// dart format off
T _$identity<T>(T value) => value; 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 /// @nodoc
mixin _$NullablePlayerSettings { mixin _$NullablePlayerSettings {
MinimizedPlayerSettings? get miniPlayerSettings =>
MinimizedPlayerSettings? get miniPlayerSettings; ExpandedPlayerSettings? get expandedPlayerSettings; double? get preferredDefaultVolume; double? get preferredDefaultSpeed; List<double>? get speedOptions; SleepTimerSettings? get sleepTimerSettings; Duration? get playbackReportInterval; throw _privateConstructorUsedError;
/// Create a copy of NullablePlayerSettings ExpandedPlayerSettings? get expandedPlayerSettings =>
/// with the given fields replaced by the non-null parameter values. throw _privateConstructorUsedError;
@JsonKey(includeFromJson: false, includeToJson: false) double? get preferredDefaultVolume => throw _privateConstructorUsedError;
@pragma('vm:prefer-inline') double? get preferredDefaultSpeed => throw _privateConstructorUsedError;
$NullablePlayerSettingsCopyWith<NullablePlayerSettings> get copyWith => _$NullablePlayerSettingsCopyWithImpl<NullablePlayerSettings>(this as NullablePlayerSettings, _$identity); List<double>? get speedOptions => throw _privateConstructorUsedError;
SleepTimerSettings? get sleepTimerSettings =>
throw _privateConstructorUsedError;
Duration? get playbackReportInterval => throw _privateConstructorUsedError;
/// Serializes this NullablePlayerSettings to a JSON map. /// Serializes this NullablePlayerSettings to a JSON map.
Map<String, dynamic> toJson(); Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
@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 /// @nodoc
abstract mixin class $NullablePlayerSettingsCopyWith<$Res> { abstract class $NullablePlayerSettingsCopyWith<$Res> {
factory $NullablePlayerSettingsCopyWith(NullablePlayerSettings value, $Res Function(NullablePlayerSettings) _then) = _$NullablePlayerSettingsCopyWithImpl; factory $NullablePlayerSettingsCopyWith(NullablePlayerSettings value,
@useResult $Res Function(NullablePlayerSettings) then) =
$Res call({ _$NullablePlayerSettingsCopyWithImpl<$Res, NullablePlayerSettings>;
MinimizedPlayerSettings? miniPlayerSettings, ExpandedPlayerSettings? expandedPlayerSettings, double? preferredDefaultVolume, double? preferredDefaultSpeed, List<double>? speedOptions, SleepTimerSettings? sleepTimerSettings, Duration? playbackReportInterval @useResult
}); $Res call(
{MinimizedPlayerSettings? miniPlayerSettings,
ExpandedPlayerSettings? expandedPlayerSettings,
$MinimizedPlayerSettingsCopyWith<$Res>? get miniPlayerSettings;$ExpandedPlayerSettingsCopyWith<$Res>? get expandedPlayerSettings;$SleepTimerSettingsCopyWith<$Res>? get sleepTimerSettings; double? preferredDefaultVolume,
double? preferredDefaultSpeed,
List<double>? speedOptions,
SleepTimerSettings? sleepTimerSettings,
Duration? playbackReportInterval});
$MinimizedPlayerSettingsCopyWith<$Res>? get miniPlayerSettings;
$ExpandedPlayerSettingsCopyWith<$Res>? get expandedPlayerSettings;
$SleepTimerSettingsCopyWith<$Res>? get sleepTimerSettings;
} }
/// @nodoc /// @nodoc
class _$NullablePlayerSettingsCopyWithImpl<$Res> class _$NullablePlayerSettingsCopyWithImpl<$Res,
$Val extends NullablePlayerSettings>
implements $NullablePlayerSettingsCopyWith<$Res> { implements $NullablePlayerSettingsCopyWith<$Res> {
_$NullablePlayerSettingsCopyWithImpl(this._self, this._then); _$NullablePlayerSettingsCopyWithImpl(this._value, this._then);
final NullablePlayerSettings _self; // ignore: unused_field
final $Res Function(NullablePlayerSettings) _then; final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of NullablePlayerSettings /// Create a copy of NullablePlayerSettings
/// with the given fields replaced by the non-null parameter values. /// 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,}) { @pragma('vm:prefer-inline')
return _then(_self.copyWith( @override
miniPlayerSettings: freezed == miniPlayerSettings ? _self.miniPlayerSettings : miniPlayerSettings // ignore: cast_nullable_to_non_nullable $Res call({
as MinimizedPlayerSettings?,expandedPlayerSettings: freezed == expandedPlayerSettings ? _self.expandedPlayerSettings : expandedPlayerSettings // ignore: cast_nullable_to_non_nullable Object? miniPlayerSettings = freezed,
as ExpandedPlayerSettings?,preferredDefaultVolume: freezed == preferredDefaultVolume ? _self.preferredDefaultVolume : preferredDefaultVolume // ignore: cast_nullable_to_non_nullable Object? expandedPlayerSettings = freezed,
as double?,preferredDefaultSpeed: freezed == preferredDefaultSpeed ? _self.preferredDefaultSpeed : preferredDefaultSpeed // ignore: cast_nullable_to_non_nullable Object? preferredDefaultVolume = freezed,
as double?,speedOptions: freezed == speedOptions ? _self.speedOptions : speedOptions // ignore: cast_nullable_to_non_nullable Object? preferredDefaultSpeed = freezed,
as List<double>?,sleepTimerSettings: freezed == sleepTimerSettings ? _self.sleepTimerSettings : sleepTimerSettings // ignore: cast_nullable_to_non_nullable Object? speedOptions = freezed,
as SleepTimerSettings?,playbackReportInterval: freezed == playbackReportInterval ? _self.playbackReportInterval : playbackReportInterval // ignore: cast_nullable_to_non_nullable Object? sleepTimerSettings = freezed,
as Duration?, 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.
@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);
});
}
/// 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);
});
}
/// 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);
});
}
}
/// @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;
}
/// @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?,
)); ));
}
/// 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));
});
}
}
/// 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 /// @nodoc
@JsonSerializable() @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;
class _NullablePlayerSettings implements NullablePlayerSettings { factory _$NullablePlayerSettingsImpl.fromJson(Map<String, dynamic> json) =>
const _NullablePlayerSettings({this.miniPlayerSettings, this.expandedPlayerSettings, this.preferredDefaultVolume, this.preferredDefaultSpeed, final List<double>? speedOptions, this.sleepTimerSettings, this.playbackReportInterval}): _speedOptions = speedOptions; _$$NullablePlayerSettingsImplFromJson(json);
factory _NullablePlayerSettings.fromJson(Map<String, dynamic> json) => _$NullablePlayerSettingsFromJson(json);
@override final MinimizedPlayerSettings? miniPlayerSettings; @override
@override final ExpandedPlayerSettings? expandedPlayerSettings; final MinimizedPlayerSettings? miniPlayerSettings;
@override final double? preferredDefaultVolume; @override
@override final double? preferredDefaultSpeed; final ExpandedPlayerSettings? expandedPlayerSettings;
@override
final double? preferredDefaultVolume;
@override
final double? preferredDefaultSpeed;
final List<double>? _speedOptions; final List<double>? _speedOptions;
@override List<double>? get speedOptions { @override
List<double>? get speedOptions {
final value = _speedOptions; final value = _speedOptions;
if (value == null) return null; if (value == null) return null;
if (_speedOptions is EqualUnmodifiableListView) return _speedOptions; if (_speedOptions is EqualUnmodifiableListView) return _speedOptions;
// ignore: implicit_dynamic_type // ignore: implicit_dynamic_type
return EqualUnmodifiableListView(value); return EqualUnmodifiableListView(value);
} }
@override final SleepTimerSettings? sleepTimerSettings; @override
@override final Duration? playbackReportInterval; final SleepTimerSettings? sleepTimerSettings;
@override
final Duration? playbackReportInterval;
/// Create a copy of NullablePlayerSettings @override
/// with the given fields replaced by the non-null parameter values. String toString() {
@override @JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
_$NullablePlayerSettingsCopyWith<_NullablePlayerSettings> get copyWith => __$NullablePlayerSettingsCopyWithImpl<_NullablePlayerSettings>(this, _$identity);
@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)'; 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) { @override
return _then(_self.copyWith(miniPlayerSettings: value)); bool operator ==(Object other) {
}); return identical(this, other) ||
}/// Create a copy of NullablePlayerSettings (other.runtimeType == runtimeType &&
/// with the given fields replaced by the non-null parameter values. other is _$NullablePlayerSettingsImpl &&
@override (identical(other.miniPlayerSettings, miniPlayerSettings) ||
@pragma('vm:prefer-inline') other.miniPlayerSettings == miniPlayerSettings) &&
$ExpandedPlayerSettingsCopyWith<$Res>? get expandedPlayerSettings { (identical(other.expandedPlayerSettings, expandedPlayerSettings) ||
if (_self.expandedPlayerSettings == null) { other.expandedPlayerSettings == expandedPlayerSettings) &&
return null; (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));
} }
return $ExpandedPlayerSettingsCopyWith<$Res>(_self.expandedPlayerSettings!, (value) { @JsonKey(includeFromJson: false, includeToJson: false)
return _then(_self.copyWith(expandedPlayerSettings: value)); @override
}); int get hashCode => Object.hash(
}/// Create a copy of NullablePlayerSettings runtimeType,
/// with the given fields replaced by the non-null parameter values. miniPlayerSettings,
@override expandedPlayerSettings,
@pragma('vm:prefer-inline') preferredDefaultVolume,
$SleepTimerSettingsCopyWith<$Res>? get sleepTimerSettings { preferredDefaultSpeed,
if (_self.sleepTimerSettings == null) { const DeepCollectionEquality().hash(_speedOptions),
return null; 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,
);
} }
return $SleepTimerSettingsCopyWith<$Res>(_self.sleepTimerSettings!, (value) {
return _then(_self.copyWith(sleepTimerSettings: value));
});
}
} }
// dart format on 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;
factory _NullablePlayerSettings.fromJson(Map<String, dynamic> json) =
_$NullablePlayerSettingsImpl.fromJson;
@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;
}

View file

@ -6,37 +6,37 @@ part of 'nullable_player_settings.dart';
// JsonSerializableGenerator // JsonSerializableGenerator
// ************************************************************************** // **************************************************************************
_NullablePlayerSettings _$NullablePlayerSettingsFromJson( _$NullablePlayerSettingsImpl _$$NullablePlayerSettingsImplFromJson(
Map<String, dynamic> json, Map<String, dynamic> json) =>
) => _NullablePlayerSettings( _$NullablePlayerSettingsImpl(
miniPlayerSettings: json['miniPlayerSettings'] == null miniPlayerSettings: json['miniPlayerSettings'] == null
? null ? null
: MinimizedPlayerSettings.fromJson( : MinimizedPlayerSettings.fromJson(
json['miniPlayerSettings'] as Map<String, dynamic>, json['miniPlayerSettings'] as Map<String, dynamic>),
),
expandedPlayerSettings: json['expandedPlayerSettings'] == null expandedPlayerSettings: json['expandedPlayerSettings'] == null
? null ? null
: ExpandedPlayerSettings.fromJson( : ExpandedPlayerSettings.fromJson(
json['expandedPlayerSettings'] as Map<String, dynamic>, json['expandedPlayerSettings'] as Map<String, dynamic>),
), preferredDefaultVolume:
preferredDefaultVolume: (json['preferredDefaultVolume'] as num?)?.toDouble(), (json['preferredDefaultVolume'] as num?)?.toDouble(),
preferredDefaultSpeed: (json['preferredDefaultSpeed'] as num?)?.toDouble(), preferredDefaultSpeed:
(json['preferredDefaultSpeed'] as num?)?.toDouble(),
speedOptions: (json['speedOptions'] as List<dynamic>?) speedOptions: (json['speedOptions'] as List<dynamic>?)
?.map((e) => (e as num).toDouble()) ?.map((e) => (e as num).toDouble())
.toList(), .toList(),
sleepTimerSettings: json['sleepTimerSettings'] == null sleepTimerSettings: json['sleepTimerSettings'] == null
? null ? null
: SleepTimerSettings.fromJson( : SleepTimerSettings.fromJson(
json['sleepTimerSettings'] as Map<String, dynamic>, json['sleepTimerSettings'] as Map<String, dynamic>),
),
playbackReportInterval: json['playbackReportInterval'] == null playbackReportInterval: json['playbackReportInterval'] == null
? null ? null
: Duration(microseconds: (json['playbackReportInterval'] as num).toInt()), : Duration(
); microseconds: (json['playbackReportInterval'] as num).toInt()),
);
Map<String, dynamic> _$NullablePlayerSettingsToJson( Map<String, dynamic> _$$NullablePlayerSettingsImplToJson(
_NullablePlayerSettings instance, _$NullablePlayerSettingsImpl instance) =>
) => <String, dynamic>{ <String, dynamic>{
'miniPlayerSettings': instance.miniPlayerSettings, 'miniPlayerSettings': instance.miniPlayerSettings,
'expandedPlayerSettings': instance.expandedPlayerSettings, 'expandedPlayerSettings': instance.expandedPlayerSettings,
'preferredDefaultVolume': instance.preferredDefaultVolume, 'preferredDefaultVolume': instance.preferredDefaultVolume,
@ -44,4 +44,4 @@ Map<String, dynamic> _$NullablePlayerSettingsToJson(
'speedOptions': instance.speedOptions, 'speedOptions': instance.speedOptions,
'sleepTimerSettings': instance.sleepTimerSettings, 'sleepTimerSettings': instance.sleepTimerSettings,
'playbackReportInterval': instance.playbackReportInterval?.inMicroseconds, 'playbackReportInterval': instance.playbackReportInterval?.inMicroseconds,
}; };

View file

@ -6,102 +6,171 @@ part of 'book_settings_provider.dart';
// RiverpodGenerator // RiverpodGenerator
// ************************************************************************** // **************************************************************************
// GENERATED CODE - DO NOT MODIFY BY HAND String _$bookSettingsHash() => r'b976df954edf98ec6ccb3eb41e9d07dd4a9193eb';
// ignore_for_file: type=lint, type=warning
@ProviderFor(BookSettings) /// Copied from Dart SDK
final bookSettingsProvider = BookSettingsFamily._(); class _SystemHash {
_SystemHash._();
final class BookSettingsProvider static int combine(int hash, int value) {
extends $NotifierProvider<BookSettings, model.BookSettings> { // ignore: parameter_assignments
BookSettingsProvider._({ hash = 0x1fffffff & (hash + value);
required BookSettingsFamily super.from, // ignore: parameter_assignments
required String super.argument, hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
}) : super( return hash ^ (hash >> 6);
retry: null,
name: r'bookSettingsProvider',
isAutoDispose: true,
dependencies: null,
$allTransitiveDependencies: null,
);
@override
String debugGetCreateSourceHash() => _$bookSettingsHash();
@override
String toString() {
return r'bookSettingsProvider'
''
'($argument)';
} }
@$internal static int finish(int hash) {
@override // ignore: parameter_assignments
BookSettings create() => BookSettings(); hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
// ignore: parameter_assignments
hash = hash ^ (hash >> 11);
return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
}
}
/// {@macro riverpod.override_with_value} abstract class _$BookSettings
Override overrideWithValue(model.BookSettings value) { extends BuildlessAutoDisposeNotifier<model.BookSettings> {
return $ProviderOverride( late final String bookId;
origin: this,
providerOverride: $SyncValueProvider<model.BookSettings>(value), model.BookSettings build(
String bookId,
); );
}
/// See also [BookSettings].
@ProviderFor(BookSettings)
const bookSettingsProvider = BookSettingsFamily();
/// See also [BookSettings].
class BookSettingsFamily extends Family<model.BookSettings> {
/// See also [BookSettings].
const BookSettingsFamily();
/// See also [BookSettings].
BookSettingsProvider call(
String bookId,
) {
return BookSettingsProvider(
bookId,
);
}
@override
BookSettingsProvider getProviderOverride(
covariant BookSettingsProvider provider,
) {
return call(
provider.bookId,
);
}
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(
origin: this,
override: BookSettingsProvider._internal(
() => create()..bookId = bookId,
from: from,
name: null,
dependencies: null,
allTransitiveDependencies: null,
debugGetCreateSourceHash: null,
bookId: bookId,
),
);
}
@override
AutoDisposeNotifierProviderElement<BookSettings, model.BookSettings>
createElement() {
return _BookSettingsProviderElement(this);
} }
@override @override
bool operator ==(Object other) { bool operator ==(Object other) {
return other is BookSettingsProvider && other.argument == argument; return other is BookSettingsProvider && other.bookId == bookId;
} }
@override @override
int get hashCode { int get hashCode {
return argument.hashCode; var hash = _SystemHash.combine(0, runtimeType.hashCode);
hash = _SystemHash.combine(hash, bookId.hashCode);
return _SystemHash.finish(hash);
} }
} }
String _$bookSettingsHash() => r'b976df954edf98ec6ccb3eb41e9d07dd4a9193eb'; @Deprecated('Will be removed in 3.0. Use Ref instead')
// ignore: unused_element
final class BookSettingsFamily extends $Family mixin BookSettingsRef on AutoDisposeNotifierProviderRef<model.BookSettings> {
with /// The parameter `bookId` of this provider.
$ClassFamilyOverride< String get bookId;
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 toString() => r'bookSettingsProvider';
} }
abstract class _$BookSettings extends $Notifier<model.BookSettings> { class _BookSettingsProviderElement
late final _$args = ref.$arg as String; extends AutoDisposeNotifierProviderElement<BookSettings, model.BookSettings>
String get bookId => _$args; with BookSettingsRef {
_BookSettingsProviderElement(super.provider);
model.BookSettings build(String bookId);
@$mustCallSuper
@override @override
void runBuild() { String get bookId => (origin as BookSettingsProvider).bookId;
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

View file

@ -126,7 +126,9 @@ class PlaybackReporter {
} }
Future<void> tryReportPlayback(_) async { Future<void> tryReportPlayback(_) async {
_logger.fine('callback called when elapsed ${_stopwatch.elapsed}'); _logger.fine(
'callback called when elapsed ${_stopwatch.elapsed}',
);
if (player.book != null && if (player.book != null &&
player.positionInBook >= player.positionInBook >=
player.book!.duration - markCompleteWhenTimeLeft) { player.book!.duration - markCompleteWhenTimeLeft) {

View file

@ -20,9 +20,8 @@ class PlaybackReporter extends _$PlaybackReporter {
final deviceName = await ref.watch(deviceNameProvider.future); final deviceName = await ref.watch(deviceNameProvider.future);
final deviceModel = await ref.watch(deviceModelProvider.future); final deviceModel = await ref.watch(deviceModelProvider.future);
final deviceSdkVersion = await ref.watch(deviceSdkVersionProvider.future); final deviceSdkVersion = await ref.watch(deviceSdkVersionProvider.future);
final deviceManufacturer = await ref.watch( final deviceManufacturer =
deviceManufacturerProvider.future, await ref.watch(deviceManufacturerProvider.future);
);
final reporter = core.PlaybackReporter( final reporter = core.PlaybackReporter(
player, player,

View file

@ -6,55 +6,21 @@ part of 'playback_reporter_provider.dart';
// RiverpodGenerator // 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'; String _$playbackReporterHash() => r'f5436d652e51c37bcc684acdaec94e17a97e68e5';
abstract class _$PlaybackReporter /// See also [PlaybackReporter].
extends $AsyncNotifier<core.PlaybackReporter> { @ProviderFor(PlaybackReporter)
FutureOr<core.PlaybackReporter> build(); final playbackReporterProvider =
@$mustCallSuper AsyncNotifierProvider<PlaybackReporter, core.PlaybackReporter>.internal(
@override PlaybackReporter.new,
void runBuild() { name: r'playbackReporterProvider',
final ref = debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
this.ref ? null
as $Ref<AsyncValue<core.PlaybackReporter>, core.PlaybackReporter>; : _$playbackReporterHash,
final element = dependencies: null,
ref.element allTransitiveDependencies: null,
as $ClassProviderElement< );
AnyNotifier<
AsyncValue<core.PlaybackReporter>, typedef _$PlaybackReporter = AsyncNotifier<core.PlaybackReporter>;
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
AsyncValue<core.PlaybackReporter>,
Object?,
Object?
>;
element.handleCreate(ref, build);
}
}

View file

@ -23,9 +23,7 @@ Duration sumOfTracks(BookExpanded book, int? index) {
_logger.warning('Index is null or less than 0, returning 0'); _logger.warning('Index is null or less than 0, returning 0');
return Duration.zero; return Duration.zero;
} }
final total = book.tracks final total = book.tracks.sublist(0, index).fold<Duration>(
.sublist(0, index)
.fold<Duration>(
Duration.zero, Duration.zero,
(previousValue, element) => previousValue + element.duration, (previousValue, element) => previousValue + element.duration,
); );
@ -36,10 +34,13 @@ Duration sumOfTracks(BookExpanded book, int? index) {
/// returns the [AudioTrack] to play based on the [position] in the [book] /// returns the [AudioTrack] to play based on the [position] in the [book]
AudioTrack getTrackToPlay(BookExpanded book, Duration position) { AudioTrack getTrackToPlay(BookExpanded book, Duration position) {
_logger.fine('Getting track to play for position: $position'); _logger.fine('Getting track to play for position: $position');
final track = book.tracks.firstWhere((element) { final track = book.tracks.firstWhere(
(element) {
return element.startOffset <= position && return element.startOffset <= position &&
(element.startOffset + element.duration) >= position; (element.startOffset + element.duration) >= position;
}, orElse: () => book.tracks.last); },
orElse: () => book.tracks.last,
);
_logger.fine('Track to play for position: $position is $track'); _logger.fine('Track to play for position: $position is $track');
return track; return track;
} }
@ -125,12 +126,8 @@ class AudiobookPlayer extends AudioPlayer {
ConcatenatingAudioSource( ConcatenatingAudioSource(
useLazyPreparation: true, useLazyPreparation: true,
children: book.tracks.map((track) { children: book.tracks.map((track) {
final retrievedUri = _getUri( final retrievedUri =
track, _getUri(track, downloadedUris, baseUrl: baseUrl, token: token);
downloadedUris,
baseUrl: baseUrl,
token: token,
);
_logger.fine( _logger.fine(
'Setting source for track: ${track.title}, URI: ${retrievedUri.obfuscate()}', 'Setting source for track: ${track.title}, URI: ${retrievedUri.obfuscate()}',
); );
@ -144,8 +141,7 @@ class AudiobookPlayer extends AudioPlayer {
.formatNotificationTitle(book), .formatNotificationTitle(book),
album: appSettings.notificationSettings.secondaryTitle album: appSettings.notificationSettings.secondaryTitle
.formatNotificationTitle(book), .formatNotificationTitle(book),
artUri: artUri: artworkUri ??
artworkUri ??
Uri.parse( Uri.parse(
'$baseUrl/api/items/${book.libraryItemId}/cover?token=$token&width=800', '$baseUrl/api/items/${book.libraryItemId}/cover?token=$token&width=800',
), ),
@ -259,9 +255,12 @@ class AudiobookPlayer extends AudioPlayer {
if (_book!.chapters.isEmpty) { if (_book!.chapters.isEmpty) {
return null; return null;
} }
return _book!.chapters.firstWhere((element) { return _book!.chapters.firstWhere(
(element) {
return element.start <= positionInBook && element.end >= positionInBook; return element.start <= positionInBook && element.end >= positionInBook;
}, orElse: () => _book!.chapters.first); },
orElse: () => _book!.chapters.first,
);
} }
} }
@ -272,9 +271,11 @@ Uri _getUri(
required String token, required String token,
}) { }) {
// check if the track is in the downloadedUris // check if the track is in the downloadedUris
final uri = downloadedUris?.firstWhereOrNull((element) { final uri = downloadedUris?.firstWhereOrNull(
(element) {
return element.pathSegments.last == track.metadata?.filename; return element.pathSegments.last == track.metadata?.filename;
}); },
);
return uri ?? return uri ??
Uri.parse('${baseUrl.toString()}${track.contentUrl}?token=$token'); Uri.parse('${baseUrl.toString()}${track.contentUrl}?token=$token');
@ -282,14 +283,17 @@ Uri _getUri(
extension FormatNotificationTitle on String { extension FormatNotificationTitle on String {
String formatNotificationTitle(BookExpanded book) { String formatNotificationTitle(BookExpanded book) {
return replaceAllMapped(RegExp(r'\$(\w+)'), (match) { return replaceAllMapped(
RegExp(r'\$(\w+)'),
(match) {
final type = match.group(1); final type = match.group(1);
return NotificationTitleType.values return NotificationTitleType.values
.firstWhere((element) => element.name == type) .firstWhere((element) => element.name == type)
.extractFrom(book) ?? .extractFrom(book) ??
match.group(0) ?? match.group(0) ??
''; '';
}); },
);
} }
} }

View file

@ -30,28 +30,23 @@ Future<void> configurePlayer() async {
androidShowNotificationBadge: false, androidShowNotificationBadge: false,
notificationConfigBuilder: (state) { notificationConfigBuilder: (state) {
final controls = [ final controls = [
if (appSettings.notificationSettings.mediaControls.contains( if (appSettings.notificationSettings.mediaControls
NotificationMediaControl.skipToPreviousChapter, .contains(NotificationMediaControl.skipToPreviousChapter) &&
) &&
state.hasPrevious) state.hasPrevious)
MediaControl.skipToPrevious, MediaControl.skipToPrevious,
if (appSettings.notificationSettings.mediaControls.contains( if (appSettings.notificationSettings.mediaControls
NotificationMediaControl.rewind, .contains(NotificationMediaControl.rewind))
))
MediaControl.rewind, MediaControl.rewind,
if (state.playing) MediaControl.pause else MediaControl.play, if (state.playing) MediaControl.pause else MediaControl.play,
if (appSettings.notificationSettings.mediaControls.contains( if (appSettings.notificationSettings.mediaControls
NotificationMediaControl.fastForward, .contains(NotificationMediaControl.fastForward))
))
MediaControl.fastForward, MediaControl.fastForward,
if (appSettings.notificationSettings.mediaControls.contains( if (appSettings.notificationSettings.mediaControls
NotificationMediaControl.skipToNextChapter, .contains(NotificationMediaControl.skipToNextChapter) &&
) &&
state.hasNext) state.hasNext)
MediaControl.skipToNext, MediaControl.skipToNext,
if (appSettings.notificationSettings.mediaControls.contains( if (appSettings.notificationSettings.mediaControls
NotificationMediaControl.stop, .contains(NotificationMediaControl.stop))
))
MediaControl.stop, MediaControl.stop,
]; ];
return NotificationConfig( return NotificationConfig(

View file

@ -6,57 +6,20 @@ part of 'playlist_provider.dart';
// RiverpodGenerator // 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'; String _$playlistHash() => r'bed4642e4c2de829e4d0630cb5bf92bffeeb1f60';
abstract class _$Playlist extends $Notifier<AudiobookPlaylist> { /// See also [Playlist].
AudiobookPlaylist build(); @ProviderFor(Playlist)
@$mustCallSuper final playlistProvider =
@override AutoDisposeNotifierProvider<Playlist, AudiobookPlaylist>.internal(
void runBuild() { Playlist.new,
final ref = this.ref as $Ref<AudiobookPlaylist, AudiobookPlaylist>; name: r'playlistProvider',
final element = debugGetCreateSourceHash:
ref.element const bool.fromEnvironment('dart.vm.product') ? null : _$playlistHash,
as $ClassProviderElement< dependencies: null,
AnyNotifier<AudiobookPlaylist, AudiobookPlaylist>, allTransitiveDependencies: null,
AudiobookPlaylist, );
Object?,
Object? typedef _$Playlist = AutoDisposeNotifier<AudiobookPlaylist>;
>; // ignore_for_file: type=lint
element.handleCreate(ref, build); // ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package
}
}

View file

@ -16,7 +16,10 @@ class SimpleAudiobookPlayer extends _$SimpleAudiobookPlayer {
@override @override
core.AudiobookPlayer build() { core.AudiobookPlayer build() {
final api = ref.watch(authenticatedApiProvider); 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); ref.onDispose(player.dispose);
_logger.finer('created simple player'); _logger.finer('created simple player');

View file

@ -6,119 +6,41 @@ part of 'audiobook_player.dart';
// RiverpodGenerator // 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() => String _$simpleAudiobookPlayerHash() =>
r'5e94bbff4314adceb5affa704fc4d079d4016afa'; r'5e94bbff4314adceb5affa704fc4d079d4016afa';
/// Simple because it doesn't rebuild when the player state changes /// Simple because it doesn't rebuild when the player state changes
/// it only rebuilds when the token changes /// it only rebuilds when the token changes
///
abstract class _$SimpleAudiobookPlayer extends $Notifier<core.AudiobookPlayer> { /// Copied from [SimpleAudiobookPlayer].
core.AudiobookPlayer build(); @ProviderFor(SimpleAudiobookPlayer)
@$mustCallSuper final simpleAudiobookPlayerProvider =
@override NotifierProvider<SimpleAudiobookPlayer, core.AudiobookPlayer>.internal(
void runBuild() { SimpleAudiobookPlayer.new,
final ref = this.ref as $Ref<core.AudiobookPlayer, core.AudiobookPlayer>; name: r'simpleAudiobookPlayerProvider',
final element = debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
ref.element ? null
as $ClassProviderElement< : _$simpleAudiobookPlayerHash,
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, dependencies: null,
$allTransitiveDependencies: 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),
);
}
}
typedef _$SimpleAudiobookPlayer = Notifier<core.AudiobookPlayer>;
String _$audiobookPlayerHash() => r'0f180308067486896fec6a65a6afb0e6686ac4a0'; String _$audiobookPlayerHash() => r'0f180308067486896fec6a65a6afb0e6686ac4a0';
abstract class _$AudiobookPlayer extends $Notifier<core.AudiobookPlayer> { /// See also [AudiobookPlayer].
core.AudiobookPlayer build(); @ProviderFor(AudiobookPlayer)
@$mustCallSuper final audiobookPlayerProvider =
@override NotifierProvider<AudiobookPlayer, core.AudiobookPlayer>.internal(
void runBuild() { AudiobookPlayer.new,
final ref = this.ref as $Ref<core.AudiobookPlayer, core.AudiobookPlayer>; name: r'audiobookPlayerProvider',
final element = debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
ref.element ? null
as $ClassProviderElement< : _$audiobookPlayerHash,
AnyNotifier<core.AudiobookPlayer, core.AudiobookPlayer>, dependencies: null,
core.AudiobookPlayer, allTransitiveDependencies: null,
Object?, );
Object?
>; typedef _$AudiobookPlayer = Notifier<core.AudiobookPlayer>;
element.handleCreate(ref, build); // 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
}

View file

@ -6,147 +6,66 @@ part of 'currently_playing_provider.dart';
// RiverpodGenerator // 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() => String _$currentlyPlayingBookHash() =>
r'e4258694c8f0d1e89651b330fae0f672ca13a484'; r'e4258694c8f0d1e89651b330fae0f672ca13a484';
/// provided the current chapter of the book being played /// See also [currentlyPlayingBook].
@ProviderFor(currentlyPlayingBook)
@ProviderFor(currentPlayingChapter) final currentlyPlayingBookProvider =
final currentPlayingChapterProvider = CurrentPlayingChapterProvider._(); AutoDisposeProvider<BookExpanded?>.internal(
currentlyPlayingBook,
/// provided the current chapter of the book being played name: r'currentlyPlayingBookProvider',
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
final class CurrentPlayingChapterProvider ? null
extends $FunctionalProvider<BookChapter?, BookChapter?, BookChapter?> : _$currentlyPlayingBookHash,
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, dependencies: null,
$allTransitiveDependencies: 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() => String _$currentPlayingChapterHash() =>
r'73db8b8a9058573bb0c68ec5d5f8aba9306f3d24'; r'73db8b8a9058573bb0c68ec5d5f8aba9306f3d24';
/// provides the book metadata of the currently playing book /// provided the current chapter of the book being played
///
@ProviderFor(currentBookMetadata) /// Copied from [currentPlayingChapter].
final currentBookMetadataProvider = CurrentBookMetadataProvider._(); @ProviderFor(currentPlayingChapter)
final currentPlayingChapterProvider =
/// provides the book metadata of the currently playing book AutoDisposeProvider<BookChapter?>.internal(
currentPlayingChapter,
final class CurrentBookMetadataProvider name: r'currentPlayingChapterProvider',
extends debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
$FunctionalProvider< ? null
BookMetadataExpanded?, : _$currentPlayingChapterHash,
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, dependencies: null,
$allTransitiveDependencies: 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),
);
}
}
@Deprecated('Will be removed in 3.0. Use Ref instead')
// ignore: unused_element
typedef CurrentPlayingChapterRef = AutoDisposeProviderRef<BookChapter?>;
String _$currentBookMetadataHash() => String _$currentBookMetadataHash() =>
r'f537ef4ef19280bc952de658ecf6520c535ae344'; r'f537ef4ef19280bc952de658ecf6520c535ae344';
/// 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

View file

@ -26,10 +26,11 @@ extension on Ref {
} }
@Riverpod(keepAlive: true) @Riverpod(keepAlive: true)
Raw<ValueNotifier<double>> playerExpandProgressNotifier(Ref ref) { Raw<ValueNotifier<double>> playerExpandProgressNotifier(
final ValueNotifier<double> playerExpandProgress = ValueNotifier( Ref ref,
playerMinHeight, ) {
); final ValueNotifier<double> playerExpandProgress =
ValueNotifier(playerMinHeight);
return ref.disposeAndListenChangeNotifier(playerExpandProgress); return ref.disposeAndListenChangeNotifier(playerExpandProgress);
} }
@ -45,8 +46,10 @@ Raw<ValueNotifier<double>> playerExpandProgressNotifier(Ref ref) {
// a provider that will listen to the playerExpandProgressNotifier and return the percentage of the player expanded // a provider that will listen to the playerExpandProgressNotifier and return the percentage of the player expanded
@Riverpod(keepAlive: true) @Riverpod(keepAlive: true)
double playerHeight(Ref ref) { double playerHeight(
final playerExpandProgress = ref.watch(playerExpandProgressProvider); Ref ref,
) {
final playerExpandProgress = ref.watch(playerExpandProgressNotifierProvider);
// on change of the playerExpandProgress invalidate // on change of the playerExpandProgress invalidate
playerExpandProgress.addListener(() { playerExpandProgress.addListener(() {
@ -60,7 +63,9 @@ double playerHeight(Ref ref) {
final audioBookMiniplayerController = MiniplayerController(); final audioBookMiniplayerController = MiniplayerController();
@Riverpod(keepAlive: true) @Riverpod(keepAlive: true)
bool isPlayerActive(Ref ref) { bool isPlayerActive(
Ref ref,
) {
try { try {
final player = ref.watch(audiobookPlayerProvider); final player = ref.watch(audiobookPlayerProvider);
if (player.book != null) { if (player.book != null) {

View file

@ -6,134 +6,58 @@ part of 'player_form.dart';
// RiverpodGenerator // 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() => String _$playerExpandProgressNotifierHash() =>
r'1ac7172d90a070f96222286edd1a176be197f378'; 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) @ProviderFor(playerHeight)
final playerHeightProvider = PlayerHeightProvider._(); final playerHeightProvider = Provider<double>.internal(
playerHeight,
final class PlayerHeightProvider
extends $FunctionalProvider<double, double, double>
with $Provider<double> {
PlayerHeightProvider._()
: super(
from: null,
argument: null,
retry: null,
name: r'playerHeightProvider', name: r'playerHeightProvider',
isAutoDispose: false, debugGetCreateSourceHash:
const bool.fromEnvironment('dart.vm.product') ? null : _$playerHeightHash,
dependencies: null, dependencies: null,
$allTransitiveDependencies: 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';
@ProviderFor(isPlayerActive)
final isPlayerActiveProvider = IsPlayerActiveProvider._();
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),
);
}
}
@Deprecated('Will be removed in 3.0. Use Ref instead')
// ignore: unused_element
typedef PlayerHeightRef = ProviderRef<double>;
String _$isPlayerActiveHash() => r'2c7ca125423126fb5f0ef218d37bc8fe0ca9ec98'; String _$isPlayerActiveHash() => r'2c7ca125423126fb5f0ef218d37bc8fe0ca9ec98';
/// 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,
);
@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

View file

@ -31,15 +31,19 @@ class AudiobookPlayer extends HookConsumerWidget {
if (currentBook == null) { if (currentBook == null) {
return const SizedBox.shrink(); return const SizedBox.shrink();
} }
final itemBeingPlayed = ref.watch( final itemBeingPlayed =
libraryItemProvider(currentBook.libraryItemId), ref.watch(libraryItemProvider(currentBook.libraryItemId));
);
final player = ref.watch(audiobookPlayerProvider); final player = ref.watch(audiobookPlayerProvider);
final imageOfItemBeingPlayed = itemBeingPlayed.value != null final imageOfItemBeingPlayed = itemBeingPlayed.valueOrNull != null
? ref.watch(coverImageProvider(itemBeingPlayed.value!.id)) ? ref.watch(
coverImageProvider(itemBeingPlayed.valueOrNull!.id),
)
: null; : null;
final imgWidget = imageOfItemBeingPlayed?.value != null final imgWidget = imageOfItemBeingPlayed?.valueOrNull != null
? Image.memory(imageOfItemBeingPlayed!.value!, fit: BoxFit.cover) ? Image.memory(
imageOfItemBeingPlayed!.valueOrNull!,
fit: BoxFit.cover,
)
: const BookCoverSkeleton(); : const BookCoverSkeleton();
final playPauseController = useAnimationController( final playPauseController = useAnimationController(
@ -59,10 +63,9 @@ class AudiobookPlayer extends HookConsumerWidget {
// theme from image // theme from image
final imageTheme = ref.watch( final imageTheme = ref.watch(
themeOfLibraryItemProvider( themeOfLibraryItemProvider(
itemBeingPlayed.value?.id, itemBeingPlayed.valueOrNull?.id,
brightness: Theme.of(context).brightness, brightness: Theme.of(context).brightness,
highContrast: highContrast: appSettings.themeSettings.highContrast ||
appSettings.themeSettings.highContrast ||
MediaQuery.of(context).highContrast, MediaQuery.of(context).highContrast,
), ),
); );
@ -78,16 +81,15 @@ class AudiobookPlayer extends HookConsumerWidget {
final preferredVolume = appSettings.playerSettings.preferredDefaultVolume; final preferredVolume = appSettings.playerSettings.preferredDefaultVolume;
return Theme( return Theme(
data: ThemeData( data: ThemeData(
colorScheme: imageTheme.value ?? Theme.of(context).colorScheme, colorScheme: imageTheme.valueOrNull ?? Theme.of(context).colorScheme,
), ),
child: Miniplayer( child: Miniplayer(
valueNotifier: ref.watch(playerExpandProgressProvider), valueNotifier: ref.watch(playerExpandProgressNotifierProvider),
onDragDown: (percentage) async { onDragDown: (percentage) async {
// preferred volume // preferred volume
// set volume to 0 when dragging down // set volume to 0 when dragging down
await player.setVolume( await player
preferredVolume * (1 - percentage.clamp(0, .75)), .setVolume(preferredVolume * (1 - percentage.clamp(0, .75)));
);
}, },
minHeight: playerMinHeight, minHeight: playerMinHeight,
// subtract the height of notches and other system UI // subtract the height of notches and other system UI
@ -114,7 +116,10 @@ class AudiobookPlayer extends HookConsumerWidget {
if (!isFormMiniplayer) { if (!isFormMiniplayer) {
// this calculation needs a refactor // this calculation needs a refactor
var percentageExpandedPlayer = percentage var percentageExpandedPlayer = percentage
.inverseLerp(miniplayerPercentageDeclaration, 1) .inverseLerp(
miniplayerPercentageDeclaration,
1,
)
.clamp(0.0, 1.0); .clamp(0.0, 1.0);
return PlayerWhenExpanded( return PlayerWhenExpanded(
@ -167,7 +172,9 @@ class AudiobookPlayerPlayPauseButton extends HookConsumerWidget {
await player.seek(const Duration(seconds: 0)); await player.seek(const Duration(seconds: 0));
await player.play(); await player.play();
}, },
icon: const Icon(Icons.replay), icon: const Icon(
Icons.replay,
),
), ),
ProcessingState.ready => IconButton( ProcessingState.ready => IconButton(
onPressed: () async { onPressed: () async {
@ -185,7 +192,9 @@ class AudiobookPlayerPlayPauseButton extends HookConsumerWidget {
} }
class AudiobookChapterProgressBar extends HookConsumerWidget { class AudiobookChapterProgressBar extends HookConsumerWidget {
const AudiobookChapterProgressBar({super.key}); const AudiobookChapterProgressBar({
super.key,
});
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {

View file

@ -38,7 +38,10 @@ class PlayerWhenExpanded extends HookConsumerWidget {
const lateStart = 0.4; const lateStart = 0.4;
const earlyEnd = 1; const earlyEnd = 1;
final earlyPercentage = percentageExpandedPlayer final earlyPercentage = percentageExpandedPlayer
.inverseLerp(lateStart, earlyEnd) .inverseLerp(
lateStart,
earlyEnd,
)
.clamp(0.0, 1.0); .clamp(0.0, 1.0);
final currentChapter = ref.watch(currentPlayingChapterProvider); final currentChapter = ref.watch(currentPlayingChapterProvider);
final currentBookMetadata = ref.watch(currentBookMetadataProvider); final currentBookMetadata = ref.watch(currentBookMetadataProvider);
@ -46,11 +49,15 @@ class PlayerWhenExpanded extends HookConsumerWidget {
return Column( return Column(
children: [ children: [
// sized box for system status bar; not needed as not full screen // 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 // a row with a down arrow to minimize the player, a pill shaped container to drag the player, and a cast button
ConstrainedBox( ConstrainedBox(
constraints: BoxConstraints(maxHeight: 100 * earlyPercentage), constraints: BoxConstraints(
maxHeight: 100 * earlyPercentage,
),
child: Opacity( child: Opacity(
opacity: earlyPercentage, opacity: earlyPercentage,
child: Padding( child: Padding(
@ -97,9 +104,10 @@ class PlayerWhenExpanded extends HookConsumerWidget {
decoration: BoxDecoration( decoration: BoxDecoration(
boxShadow: [ boxShadow: [
BoxShadow( BoxShadow(
color: Theme.of( color: Theme.of(context)
context, .colorScheme
).colorScheme.primary.withValues(alpha: 0.1), .primary
.withValues(alpha: 0.1),
blurRadius: 32 * earlyPercentage, blurRadius: 32 * earlyPercentage,
spreadRadius: 8 * earlyPercentage, spreadRadius: 8 * earlyPercentage,
// offset: Offset(0, 16 * earlyPercentage), // offset: Offset(0, 16 * earlyPercentage),
@ -162,9 +170,10 @@ class PlayerWhenExpanded extends HookConsumerWidget {
currentBookMetadata?.authorName ?? '', currentBookMetadata?.authorName ?? '',
].join(' - '), ].join(' - '),
style: Theme.of(context).textTheme.titleMedium?.copyWith( style: Theme.of(context).textTheme.titleMedium?.copyWith(
color: Theme.of( color: Theme.of(context)
context, .colorScheme
).colorScheme.onSurface.withValues(alpha: 0.7), .onSurface
.withValues(alpha: 0.7),
), ),
maxLines: 1, maxLines: 1,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,

View file

@ -32,10 +32,8 @@ class PlayerWhenMinimized extends HookConsumerWidget {
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
final player = ref.watch(audiobookPlayerProvider); final player = ref.watch(audiobookPlayerProvider);
final vanishingPercentage = 1 - percentageMiniplayer; final vanishingPercentage = 1 - percentageMiniplayer;
final progress = useStream( final progress =
player.slowPositionStream, useStream(player.slowPositionStream, initialData: Duration.zero);
initialData: Duration.zero,
);
final bookMetaExpanded = ref.watch(currentBookMetadataProvider); final bookMetaExpanded = ref.watch(currentBookMetadataProvider);
@ -63,7 +61,9 @@ class PlayerWhenMinimized extends HookConsumerWidget {
); );
}, },
child: ConstrainedBox( child: ConstrainedBox(
constraints: BoxConstraints(maxWidth: maxImgSize), constraints: BoxConstraints(
maxWidth: maxImgSize,
),
child: imgWidget, child: imgWidget,
), ),
), ),
@ -80,8 +80,7 @@ class PlayerWhenMinimized extends HookConsumerWidget {
// AutoScrollText( // AutoScrollText(
Text( Text(
bookMetaExpanded?.title ?? '', bookMetaExpanded?.title ?? '',
maxLines: 1, maxLines: 1, overflow: TextOverflow.ellipsis,
overflow: TextOverflow.ellipsis,
// velocity: // velocity:
// const Velocity(pixelsPerSecond: Offset(16, 0)), // const Velocity(pixelsPerSecond: Offset(16, 0)),
style: Theme.of(context).textTheme.bodyLarge, style: Theme.of(context).textTheme.bodyLarge,
@ -91,9 +90,10 @@ class PlayerWhenMinimized extends HookConsumerWidget {
maxLines: 1, maxLines: 1,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
style: Theme.of(context).textTheme.bodyMedium!.copyWith( style: Theme.of(context).textTheme.bodyMedium!.copyWith(
color: Theme.of( color: Theme.of(context)
context, .colorScheme
).colorScheme.onSurface.withValues(alpha: 0.7), .onSurface
.withValues(alpha: 0.7),
), ),
), ),
], ],
@ -135,8 +135,7 @@ class PlayerWhenMinimized extends HookConsumerWidget {
SizedBox( SizedBox(
height: barHeight, height: barHeight,
child: LinearProgressIndicator( child: LinearProgressIndicator(
value: value: (progress.data ?? Duration.zero).inSeconds /
(progress.data ?? Duration.zero).inSeconds /
player.book!.duration.inSeconds, player.book!.duration.inSeconds,
color: Theme.of(context).colorScheme.onPrimaryContainer, color: Theme.of(context).colorScheme.onPrimaryContainer,
backgroundColor: Theme.of(context).colorScheme.primaryContainer, backgroundColor: Theme.of(context).colorScheme.primaryContainer,

View file

@ -4,7 +4,10 @@ import 'package:vaani/constants/sizes.dart';
import 'package:vaani/features/player/providers/audiobook_player.dart'; import 'package:vaani/features/player/providers/audiobook_player.dart';
class AudiobookPlayerSeekButton extends HookConsumerWidget { 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 /// if true, the button seeks forward, else it seeks backwards
final bool isForward; final bool isForward;

View file

@ -5,7 +5,10 @@ import 'package:vaani/constants/sizes.dart';
import 'package:vaani/features/player/providers/audiobook_player.dart'; import 'package:vaani/features/player/providers/audiobook_player.dart';
class AudiobookPlayerSeekChapterButton extends HookConsumerWidget { 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 /// if true, the button seeks forward, else it seeks backwards
final bool isForward; final bool isForward;
@ -24,7 +27,9 @@ class AudiobookPlayerSeekChapterButton extends HookConsumerWidget {
void seekForward() { void seekForward() {
final index = player.book!.chapters.indexOf(player.currentChapter!); final index = player.book!.chapters.indexOf(player.currentChapter!);
if (index < player.book!.chapters.length - 1) { 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 { } else {
player.seek(player.currentChapter!.end); player.seek(player.currentChapter!.end);
} }
@ -32,9 +37,8 @@ class AudiobookPlayerSeekChapterButton extends HookConsumerWidget {
/// seek backward to the previous chapter or the start of the current chapter /// seek backward to the previous chapter or the start of the current chapter
void seekBackward() { void seekBackward() {
final currentPlayingChapterIndex = player.book!.chapters.indexOf( final currentPlayingChapterIndex =
player.currentChapter!, player.book!.chapters.indexOf(player.currentChapter!);
);
final chapterPosition = final chapterPosition =
player.positionInBook - player.currentChapter!.start; player.positionInBook - player.currentChapter!.start;
BookChapter chapterToSeekTo; BookChapter chapterToSeekTo;
@ -45,7 +49,9 @@ class AudiobookPlayerSeekChapterButton extends HookConsumerWidget {
} else { } else {
chapterToSeekTo = player.currentChapter!; chapterToSeekTo = player.currentChapter!;
} }
player.seek(chapterToSeekTo.start + offset); player.seek(
chapterToSeekTo.start + offset,
);
} }
return IconButton( return IconButton(

View file

@ -15,7 +15,9 @@ import 'package:vaani/shared/extensions/duration_format.dart'
import 'package:vaani/shared/hooks.dart' show useTimer; import 'package:vaani/shared/hooks.dart' show useTimer;
class ChapterSelectionButton extends HookConsumerWidget { class ChapterSelectionButton extends HookConsumerWidget {
const ChapterSelectionButton({super.key}); const ChapterSelectionButton({
super.key,
});
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
@ -47,7 +49,9 @@ class ChapterSelectionButton extends HookConsumerWidget {
} }
class ChapterSelectionModal extends HookConsumerWidget { class ChapterSelectionModal extends HookConsumerWidget {
const ChapterSelectionModal({super.key}); const ChapterSelectionModal({
super.key,
});
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
@ -83,10 +87,10 @@ class ChapterSelectionModal extends HookConsumerWidget {
child: currentBook?.chapters == null child: currentBook?.chapters == null
? const Text('No chapters found') ? const Text('No chapters found')
: Column( : Column(
children: currentBook!.chapters.map((chapter) { children: currentBook!.chapters.map(
(chapter) {
final isCurrent = currentChapterIndex == chapter.id; final isCurrent = currentChapterIndex == chapter.id;
final isPlayed = final isPlayed = currentChapterIndex != null &&
currentChapterIndex != null &&
chapter.id < currentChapterIndex; chapter.id < currentChapterIndex;
return ListTile( return ListTile(
autofocus: isCurrent, autofocus: isCurrent,
@ -116,7 +120,8 @@ class ChapterSelectionModal extends HookConsumerWidget {
notifier.play(); notifier.play();
}, },
); );
}).toList(), },
).toList(),
), ),
), ),
), ),

View file

@ -10,7 +10,9 @@ import 'package:vaani/settings/app_settings_provider.dart';
final _logger = Logger('PlayerSpeedAdjustButton'); final _logger = Logger('PlayerSpeedAdjustButton');
class PlayerSpeedAdjustButton extends HookConsumerWidget { class PlayerSpeedAdjustButton extends HookConsumerWidget {
const PlayerSpeedAdjustButton({super.key}); const PlayerSpeedAdjustButton({
super.key,
});
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
@ -33,19 +35,21 @@ class PlayerSpeedAdjustButton extends HookConsumerWidget {
notifier.setSpeed(speed); notifier.setSpeed(speed);
if (appSettings.playerSettings.configurePlayerForEveryBook) { if (appSettings.playerSettings.configurePlayerForEveryBook) {
ref ref
.read(bookSettingsProvider(bookId).notifier) .read(
bookSettingsProvider(bookId).notifier,
)
.update( .update(
bookSettings.copyWith.playerSettings( bookSettings.copyWith
preferredDefaultSpeed: speed, .playerSettings(preferredDefaultSpeed: speed),
),
); );
} else { } else {
ref ref
.read(appSettingsProvider.notifier) .read(
appSettingsProvider.notifier,
)
.update( .update(
appSettings.copyWith.playerSettings( appSettings.copyWith
preferredDefaultSpeed: speed, .playerSettings(preferredDefaultSpeed: speed),
),
); );
} }
}, },

View file

@ -59,11 +59,8 @@ class _PlayingIndicatorIconState extends State<PlayingIndicatorIcon> {
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_animationParams = List.generate( _animationParams =
widget.barCount, List.generate(widget.barCount, _createRandomParams, growable: false);
_createRandomParams,
growable: false,
);
} }
// Helper to generate random parameters for one bar's animation cycle // Helper to generate random parameters for one bar's animation cycle
@ -75,12 +72,10 @@ class _PlayingIndicatorIconState extends State<PlayingIndicatorIcon> {
// Note: These factors represent the scale relative to the *half-height* // Note: These factors represent the scale relative to the *half-height*
// if centerSymmetric is true, controlled by the alignment in scaleY. // if centerSymmetric is true, controlled by the alignment in scaleY.
final targetHeightFactor1 = final targetHeightFactor1 = widget.minHeightFactor +
widget.minHeightFactor +
_random.nextDouble() * _random.nextDouble() *
(widget.maxHeightFactor - widget.minHeightFactor); (widget.maxHeightFactor - widget.minHeightFactor);
final targetHeightFactor2 = final targetHeightFactor2 = widget.minHeightFactor +
widget.minHeightFactor +
_random.nextDouble() * _random.nextDouble() *
(widget.maxHeightFactor - widget.minHeightFactor); (widget.maxHeightFactor - widget.minHeightFactor);
@ -100,8 +95,7 @@ class _PlayingIndicatorIconState extends State<PlayingIndicatorIcon> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final color = final color = widget.color ??
widget.color ??
IconTheme.of(context).color ?? IconTheme.of(context).color ??
Theme.of(context).colorScheme.primary; Theme.of(context).colorScheme.primary;
@ -116,9 +110,8 @@ class _PlayingIndicatorIconState extends State<PlayingIndicatorIcon> {
final double maxHeight = widget.size; final double maxHeight = widget.size;
// Determine the alignment for scaling based on the symmetric flag // Determine the alignment for scaling based on the symmetric flag
final Alignment scaleAlignment = widget.centerSymmetric final Alignment scaleAlignment =
? Alignment.center widget.centerSymmetric ? Alignment.center : Alignment.bottomCenter;
: Alignment.bottomCenter;
// Determine the cross axis alignment for the Row // Determine the cross axis alignment for the Row
final CrossAxisAlignment rowAlignment = widget.centerSymmetric final CrossAxisAlignment rowAlignment = widget.centerSymmetric
@ -136,7 +129,9 @@ class _PlayingIndicatorIconState extends State<PlayingIndicatorIcon> {
crossAxisAlignment: rowAlignment, crossAxisAlignment: rowAlignment,
// Use spaceEvenly for better distribution, especially with center alignment // Use spaceEvenly for better distribution, especially with center alignment
mainAxisAlignment: MainAxisAlignment.spaceEvenly, mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: List.generate(widget.barCount, (index) { children: List.generate(
widget.barCount,
(index) {
final params = _animationParams[index]; final params = _animationParams[index];
// The actual bar widget that will be animated // The actual bar widget that will be animated
return Container( return Container(
@ -151,11 +146,14 @@ class _PlayingIndicatorIconState extends State<PlayingIndicatorIcon> {
) )
.animate( .animate(
delay: params.initialDelay, delay: params.initialDelay,
onPlay: (controller) => controller.repeat(reverse: true), onPlay: (controller) => controller.repeat(
reverse: true,
),
) )
// 1. Scale to targetHeightFactor1 // 1. Scale to targetHeightFactor1
.scaleY( .scaleY(
begin: widget.minHeightFactor, // Scale factor starts near min begin:
widget.minHeightFactor, // Scale factor starts near min
end: params.targetHeightFactor1, end: params.targetHeightFactor1,
duration: params.duration1, duration: params.duration1,
curve: Curves.easeInOutCirc, curve: Curves.easeInOutCirc,
@ -169,7 +167,9 @@ class _PlayingIndicatorIconState extends State<PlayingIndicatorIcon> {
curve: Curves.easeInOutCirc, curve: Curves.easeInOutCirc,
alignment: scaleAlignment, // Apply chosen alignment alignment: scaleAlignment, // Apply chosen alignment
); );
}, growable: false), },
growable: false,
),
), ),
), ),
); );

View file

@ -10,7 +10,10 @@ import 'package:vaani/settings/app_settings_provider.dart';
const double itemExtent = 25; const double itemExtent = 25;
class SpeedSelector extends HookConsumerWidget { class SpeedSelector extends HookConsumerWidget {
const SpeedSelector({super.key, required this.onSpeedSelected}); const SpeedSelector({
super.key,
required this.onSpeedSelected,
});
final void Function(double speed) onSpeedSelected; final void Function(double speed) onSpeedSelected;
@ -23,22 +26,34 @@ class SpeedSelector extends HookConsumerWidget {
final speedState = useState(currentSpeed); final speedState = useState(currentSpeed);
// hook the onSpeedSelected function to the state // hook the onSpeedSelected function to the state
useEffect(() { useEffect(
() {
onSpeedSelected(speedState.value); onSpeedSelected(speedState.value);
return null; return null;
}, [speedState.value]); },
[speedState.value],
);
// the speed options // the speed options
final minSpeed = min(speeds.reduce(min), playerSettings.minSpeed); final minSpeed = min(
final maxSpeed = max(speeds.reduce(max), playerSettings.maxSpeed); speeds.reduce(min),
playerSettings.minSpeed,
);
final maxSpeed = max(
speeds.reduce(max),
playerSettings.maxSpeed,
);
final speedIncrement = playerSettings.speedIncrement; final speedIncrement = playerSettings.speedIncrement;
final availableSpeeds = ((maxSpeed - minSpeed) / speedIncrement).ceil() + 1; final availableSpeeds = ((maxSpeed - minSpeed) / speedIncrement).ceil() + 1;
final availableSpeedsList = List.generate(availableSpeeds, (index) { final availableSpeedsList = List.generate(
availableSpeeds,
(index) {
// need to round to 2 decimal place to avoid floating point errors // need to round to 2 decimal place to avoid floating point errors
return double.parse( return double.parse(
(minSpeed + index * speedIncrement).toStringAsFixed(2), (minSpeed + index * speedIncrement).toStringAsFixed(2),
); );
}); },
);
final scrollController = useFixedExtentScrollController( final scrollController = useFixedExtentScrollController(
initialItem: availableSpeedsList.indexOf(currentSpeed), initialItem: availableSpeedsList.indexOf(currentSpeed),
@ -92,19 +107,18 @@ class SpeedSelector extends HookConsumerWidget {
(speed) => TextButton( (speed) => TextButton(
style: speed == speedState.value style: speed == speedState.value
? TextButton.styleFrom( ? TextButton.styleFrom(
backgroundColor: Theme.of( backgroundColor:
context, Theme.of(context).colorScheme.primaryContainer,
).colorScheme.primaryContainer, foregroundColor: Theme.of(context)
foregroundColor: Theme.of( .colorScheme
context, .onPrimaryContainer,
).colorScheme.onPrimaryContainer,
) )
// border if not selected // border if not selected
: TextButton.styleFrom( : TextButton.styleFrom(
side: BorderSide( side: BorderSide(
color: Theme.of( color: Theme.of(context)
context, .colorScheme
).colorScheme.primaryContainer, .primaryContainer,
), ),
), ),
onPressed: () async { onPressed: () async {
@ -181,13 +195,14 @@ class SpeedWheel extends StatelessWidget {
controller: scrollController, controller: scrollController,
scrollDirection: Axis.horizontal, scrollDirection: Axis.horizontal,
itemExtent: itemExtent, itemExtent: itemExtent,
diameterRatio: 1.5, diameterRatio: 1.5, squeeze: 1.2,
squeeze: 1.2,
// useMagnifier: true, // useMagnifier: true,
// magnification: 1.5, // magnification: 1.5,
physics: const FixedExtentScrollPhysics(), physics: const FixedExtentScrollPhysics(),
children: availableSpeedsList children: availableSpeedsList
.map((speed) => SpeedLine(speed: speed)) .map(
(speed) => SpeedLine(speed: speed),
)
.toList(), .toList(),
onSelectedItemChanged: (index) { onSelectedItemChanged: (index) {
speedState.value = availableSpeedsList[index]; speedState.value = availableSpeedsList[index];
@ -217,7 +232,10 @@ class SpeedWheel extends StatelessWidget {
} }
class SpeedLine extends StatelessWidget { class SpeedLine extends StatelessWidget {
const SpeedLine({super.key, required this.speed}); const SpeedLine({
super.key,
required this.speed,
});
final double speed; final double speed;

View file

@ -37,9 +37,8 @@ class ShakeDetector {
return; return;
} }
_accelerometerSubscription = _accelerometerSubscription =
userAccelerometerEventStream( userAccelerometerEventStream(samplingPeriod: _settings.samplingPeriod)
samplingPeriod: _settings.samplingPeriod, .listen((event) {
).listen((event) {
_logger.finest('RMS: ${event.rms}'); _logger.finest('RMS: ${event.rms}');
if (event.rms > _settings.threshold) { if (event.rms > _settings.threshold) {
_currentShakeCount++; _currentShakeCount++;

View file

@ -59,15 +59,16 @@ class ShakeDetector extends _$ShakeDetector {
final sleepTimer = ref.watch(sleepTimerProvider); final sleepTimer = ref.watch(sleepTimerProvider);
if (!shakeDetectionSettings.shakeAction.isPlaybackManagementEnabled && if (!shakeDetectionSettings.shakeAction.isPlaybackManagementEnabled &&
sleepTimer == null) { sleepTimer == null) {
_logger.config( _logger
'No playback management is enabled and sleep timer is off, ' .config('No playback management is enabled and sleep timer is off, '
'so shake detection is disabled', 'so shake detection is disabled');
);
return null; return null;
} }
_logger.config('Creating shake detector'); _logger.config('Creating shake detector');
final detector = core.ShakeDetector(shakeDetectionSettings, () { final detector = core.ShakeDetector(
shakeDetectionSettings,
() {
final wasActionComplete = doShakeAction( final wasActionComplete = doShakeAction(
shakeDetectionSettings.shakeAction, shakeDetectionSettings.shakeAction,
ref: ref, ref: ref,
@ -75,13 +76,17 @@ class ShakeDetector extends _$ShakeDetector {
if (wasActionComplete) { if (wasActionComplete) {
shakeDetectionSettings.feedback.forEach(postShakeFeedback); shakeDetectionSettings.feedback.forEach(postShakeFeedback);
} }
}); },
);
ref.onDispose(detector.dispose); ref.onDispose(detector.dispose);
return detector; return detector;
} }
/// Perform the shake action and return whether the action was successful /// 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); final player = ref.read(simpleAudiobookPlayerProvider);
if (player.book == null && shakeAction.isPlaybackManagementEnabled) { if (player.book == null && shakeAction.isPlaybackManagementEnabled) {
_logger.warning('No book is loaded'); _logger.warning('No book is loaded');
@ -161,11 +166,8 @@ extension on ShakeAction {
} }
bool get isPlaybackManagementEnabled { bool get isPlaybackManagementEnabled {
return { return {ShakeAction.playPause, ShakeAction.fastForward, ShakeAction.rewind}
ShakeAction.playPause, .contains(this);
ShakeAction.fastForward,
ShakeAction.rewind,
}.contains(this);
} }
bool get shouldActOnSleepTimer { bool get shouldActOnSleepTimer {

View file

@ -6,57 +6,21 @@ part of 'shake_detector.dart';
// RiverpodGenerator // 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'; String _$shakeDetectorHash() => r'2a380bab1d4021d05d2ae40fec964a5f33d3730c';
abstract class _$ShakeDetector extends $Notifier<core.ShakeDetector?> { /// See also [ShakeDetector].
core.ShakeDetector? build(); @ProviderFor(ShakeDetector)
@$mustCallSuper final shakeDetectorProvider =
@override AutoDisposeNotifierProvider<ShakeDetector, core.ShakeDetector?>.internal(
void runBuild() { ShakeDetector.new,
final ref = this.ref as $Ref<core.ShakeDetector?, core.ShakeDetector?>; name: r'shakeDetectorProvider',
final element = debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
ref.element ? null
as $ClassProviderElement< : _$shakeDetectorHash,
AnyNotifier<core.ShakeDetector?, core.ShakeDetector?>, dependencies: null,
core.ShakeDetector?, allTransitiveDependencies: null,
Object?, );
Object?
>; typedef _$ShakeDetector = AutoDisposeNotifier<core.ShakeDetector?>;
element.handleCreate(ref, build); // 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
}

View file

@ -94,7 +94,9 @@ class SleepTimer {
} }
/// starts the timer with the given duration or the default duration /// starts the timer with the given duration or the default duration
void startCountDown([Duration? forDuration]) { void startCountDown([
Duration? forDuration,
]) {
clearCountDownTimer(); clearCountDownTimer();
duration = forDuration ?? duration; duration = forDuration ?? duration;
timer = Timer(duration, () { timer = Timer(duration, () {

View file

@ -6,57 +6,20 @@ part of 'sleep_timer_provider.dart';
// RiverpodGenerator // 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'; String _$sleepTimerHash() => r'2679454a217d0630a833d730557ab4e4feac2e56';
abstract class _$SleepTimer extends $Notifier<core.SleepTimer?> { /// See also [SleepTimer].
core.SleepTimer? build(); @ProviderFor(SleepTimer)
@$mustCallSuper final sleepTimerProvider =
@override NotifierProvider<SleepTimer, core.SleepTimer?>.internal(
void runBuild() { SleepTimer.new,
final ref = this.ref as $Ref<core.SleepTimer?, core.SleepTimer?>; name: r'sleepTimerProvider',
final element = debugGetCreateSourceHash:
ref.element const bool.fromEnvironment('dart.vm.product') ? null : _$sleepTimerHash,
as $ClassProviderElement< dependencies: null,
AnyNotifier<core.SleepTimer?, core.SleepTimer?>, allTransitiveDependencies: null,
core.SleepTimer?, );
Object?,
Object? typedef _$SleepTimer = Notifier<core.SleepTimer?>;
>; // ignore_for_file: type=lint
element.handleCreate(ref, build); // ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package
}
}

View file

@ -13,7 +13,9 @@ import 'package:vaani/settings/app_settings_provider.dart';
import 'package:vaani/shared/extensions/duration_format.dart'; import 'package:vaani/shared/extensions/duration_format.dart';
class SleepTimerButton extends HookConsumerWidget { class SleepTimerButton extends HookConsumerWidget {
const SleepTimerButton({super.key}); const SleepTimerButton({
super.key,
});
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
@ -45,9 +47,8 @@ class SleepTimerButton extends HookConsumerWidget {
); );
pendingPlayerModals--; pendingPlayerModals--;
ref.read(sleepTimerProvider.notifier).setTimer(durationState.value); ref.read(sleepTimerProvider.notifier).setTimer(durationState.value);
appLogger.fine( appLogger
'Sleep Timer dialog closed with ${durationState.value}', .fine('Sleep Timer dialog closed with ${durationState.value}');
);
}, },
child: AnimatedSwitcher( child: AnimatedSwitcher(
duration: const Duration(milliseconds: 300), duration: const Duration(milliseconds: 300),
@ -56,7 +57,9 @@ class SleepTimerButton extends HookConsumerWidget {
Symbols.bedtime, Symbols.bedtime,
color: Theme.of(context).colorScheme.onSurface, color: Theme.of(context).colorScheme.onSurface,
) )
: RemainingSleepTimeDisplay(timer: sleepTimer), : RemainingSleepTimeDisplay(
timer: sleepTimer,
),
), ),
), ),
); );
@ -64,7 +67,10 @@ class SleepTimerButton extends HookConsumerWidget {
} }
class SleepTimerBottomSheet extends HookConsumerWidget { class SleepTimerBottomSheet extends HookConsumerWidget {
const SleepTimerBottomSheet({super.key, this.onDurationSelected}); const SleepTimerBottomSheet({
super.key,
this.onDurationSelected,
});
final void Function(Duration?)? onDurationSelected; final void Function(Duration?)? onDurationSelected;
@ -85,9 +91,8 @@ class SleepTimerBottomSheet extends HookConsumerWidget {
]; ];
final scrollController = useFixedExtentScrollController( final scrollController = useFixedExtentScrollController(
initialItem: allPossibleDurations.indexOf( initialItem:
sleepTimer?.duration ?? minDuration, allPossibleDurations.indexOf(sleepTimer?.duration ?? minDuration),
),
); );
final durationState = useState<Duration>( final durationState = useState<Duration>(
@ -95,10 +100,13 @@ class SleepTimerBottomSheet extends HookConsumerWidget {
); );
// useEffect to rebuild the sleep timer when the duration changes // useEffect to rebuild the sleep timer when the duration changes
useEffect(() { useEffect(
() {
onDurationSelected?.call(durationState.value); onDurationSelected?.call(durationState.value);
return null; return null;
}, [durationState.value]); },
[durationState.value],
);
return Column( return Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
@ -163,19 +171,18 @@ class SleepTimerBottomSheet extends HookConsumerWidget {
(timerDuration) => TextButton( (timerDuration) => TextButton(
style: timerDuration == durationState.value style: timerDuration == durationState.value
? TextButton.styleFrom( ? TextButton.styleFrom(
backgroundColor: Theme.of( backgroundColor:
context, Theme.of(context).colorScheme.primaryContainer,
).colorScheme.primaryContainer, foregroundColor: Theme.of(context)
foregroundColor: Theme.of( .colorScheme
context, .onPrimaryContainer,
).colorScheme.onPrimaryContainer,
) )
// border if not selected // border if not selected
: TextButton.styleFrom( : TextButton.styleFrom(
side: BorderSide( side: BorderSide(
color: Theme.of( color: Theme.of(context)
context, .colorScheme
).colorScheme.primaryContainer, .primaryContainer,
), ),
), ),
onPressed: () async { onPressed: () async {
@ -208,7 +215,10 @@ class SleepTimerBottomSheet extends HookConsumerWidget {
} }
class RemainingSleepTimeDisplay extends HookConsumerWidget { class RemainingSleepTimeDisplay extends HookConsumerWidget {
const RemainingSleepTimeDisplay({super.key, required this.timer}); const RemainingSleepTimeDisplay({
super.key,
required this.timer,
});
final SleepTimer timer; final SleepTimer timer;
@ -220,7 +230,10 @@ class RemainingSleepTimeDisplay extends HookConsumerWidget {
color: Theme.of(context).colorScheme.primary, color: Theme.of(context).colorScheme.primary,
borderRadius: BorderRadius.circular(16), borderRadius: BorderRadius.circular(16),
), ),
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), padding: const EdgeInsets.symmetric(
horizontal: 8,
vertical: 4,
),
child: Text( child: Text(
timer.timer == null timer.timer == null
? timer.duration.smartBinaryFormat ? timer.duration.smartBinaryFormat
@ -259,9 +272,8 @@ class SleepTimerWheel extends StatelessWidget {
icon: const Icon(Icons.remove), icon: const Icon(Icons.remove),
onPressed: () { onPressed: () {
// animate to index - 1 // animate to index - 1
final index = availableDurations.indexOf( final index = availableDurations
durationState.value ?? Duration.zero, .indexOf(durationState.value ?? Duration.zero);
);
if (index > 0) { if (index > 0) {
scrollController.animateToItem( scrollController.animateToItem(
index - 1, index - 1,
@ -277,13 +289,14 @@ class SleepTimerWheel extends StatelessWidget {
controller: scrollController, controller: scrollController,
scrollDirection: Axis.horizontal, scrollDirection: Axis.horizontal,
itemExtent: itemExtent, itemExtent: itemExtent,
diameterRatio: 1.5, diameterRatio: 1.5, squeeze: 1.2,
squeeze: 1.2,
// useMagnifier: true, // useMagnifier: true,
// magnification: 1.5, // magnification: 1.5,
physics: const FixedExtentScrollPhysics(), physics: const FixedExtentScrollPhysics(),
children: availableDurations children: availableDurations
.map((duration) => DurationLine(duration: duration)) .map(
(duration) => DurationLine(duration: duration),
)
.toList(), .toList(),
onSelectedItemChanged: (index) { onSelectedItemChanged: (index) {
durationState.value = availableDurations[index]; durationState.value = availableDurations[index];
@ -297,9 +310,8 @@ class SleepTimerWheel extends StatelessWidget {
icon: const Icon(Icons.add), icon: const Icon(Icons.add),
onPressed: () { onPressed: () {
// animate to index + 1 // animate to index + 1
final index = availableDurations.indexOf( final index = availableDurations
durationState.value ?? Duration.zero, .indexOf(durationState.value ?? Duration.zero);
);
if (index < availableDurations.length - 1) { if (index < availableDurations.length - 1) {
scrollController.animateToItem( scrollController.animateToItem(
index + 1, index + 1,
@ -315,7 +327,10 @@ class SleepTimerWheel extends StatelessWidget {
} }
class DurationLine extends StatelessWidget { class DurationLine extends StatelessWidget {
const DurationLine({super.key, required this.duration}); const DurationLine({
super.key,
required this.duration,
});
final Duration duration; final Duration duration;

View file

@ -20,12 +20,16 @@ import 'package:vaani/shared/extensions/obfuscation.dart' show ObfuscateSet;
import 'package:vaani/shared/widgets/add_new_server.dart' show AddNewServer; import 'package:vaani/shared/widgets/add_new_server.dart' show AddNewServer;
class ServerManagerPage extends HookConsumerWidget { class ServerManagerPage extends HookConsumerWidget {
const ServerManagerPage({super.key}); const ServerManagerPage({
super.key,
});
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
return Scaffold( return Scaffold(
appBar: AppBar(title: const Text('Manage Accounts')), appBar: AppBar(
title: const Text('Manage Accounts'),
),
body: Center( body: Center(
child: Padding( child: Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
@ -37,7 +41,9 @@ class ServerManagerPage extends HookConsumerWidget {
} }
class ServerManagerBody extends HookConsumerWidget { class ServerManagerBody extends HookConsumerWidget {
const ServerManagerBody({super.key}); const ServerManagerBody({
super.key,
});
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
@ -55,7 +61,9 @@ class ServerManagerBody extends HookConsumerWidget {
// crossAxisAlignment: CrossAxisAlignment.center, // crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.end, mainAxisAlignment: MainAxisAlignment.end,
children: [ children: [
const Text('Registered Servers'), const Text(
'Registered Servers',
),
Expanded( Expanded(
child: ListView.builder( child: ListView.builder(
itemCount: registeredServers.length, itemCount: registeredServers.length,
@ -68,12 +76,16 @@ class ServerManagerBody extends HookConsumerWidget {
'Users: ${availableUsers.where((element) => element.server == registeredServer).length}', 'Users: ${availableUsers.where((element) => element.server == registeredServer).length}',
), ),
// children are list of users of this server // children are list of users of this server
children: children: availableUsers
availableUsers .where(
.where((element) => element.server == registeredServer) (element) => element.server == registeredServer,
.map<Widget>((e) => AvailableUserTile(user: e)) )
.map<Widget>(
(e) => AvailableUserTile(user: e),
)
.nonNulls .nonNulls
.toList() .toList()
// add buttons of delete server and add user to server at the end // add buttons of delete server and add user to server at the end
..addAll([ ..addAll([
AddUserTile(server: registeredServer), AddUserTile(server: registeredServer),
@ -99,24 +111,28 @@ class ServerManagerBody extends HookConsumerWidget {
final newServer = model.AudiobookShelfServer( final newServer = model.AudiobookShelfServer(
serverUrl: makeBaseUrl(serverURIController.text), serverUrl: makeBaseUrl(serverURIController.text),
); );
ref ref.read(audiobookShelfServerProvider.notifier).addServer(
.read(audiobookShelfServerProvider.notifier) newServer,
.addServer(newServer); );
ref ref.read(apiSettingsProvider.notifier).updateState(
.read(apiSettingsProvider.notifier) apiSettings.copyWith(
.updateState( activeServer: newServer,
apiSettings.copyWith(activeServer: newServer), ),
); );
serverURIController.clear(); serverURIController.clear();
} on ServerAlreadyExistsException catch (e) { } on ServerAlreadyExistsException catch (e) {
ScaffoldMessenger.of( ScaffoldMessenger.of(context).showSnackBar(
context, SnackBar(
).showSnackBar(SnackBar(content: Text(e.toString()))); content: Text(e.toString()),
),
);
} }
} else { } else {
ScaffoldMessenger.of( ScaffoldMessenger.of(context).showSnackBar(
context, const SnackBar(
).showSnackBar(const SnackBar(content: Text('Invalid URL'))); content: Text('Invalid URL'),
),
);
} }
}, },
), ),
@ -128,7 +144,10 @@ class ServerManagerBody extends HookConsumerWidget {
} }
class DeleteServerTile extends HookConsumerWidget { class DeleteServerTile extends HookConsumerWidget {
const DeleteServerTile({super.key, required this.server}); const DeleteServerTile({
super.key,
required this.server,
});
final model.AudiobookShelfServer server; final model.AudiobookShelfServer server;
@ -148,7 +167,9 @@ class DeleteServerTile extends HookConsumerWidget {
child: Text.rich( child: Text.rich(
TextSpan( TextSpan(
children: [ children: [
const TextSpan(text: 'This will remove the server '), const TextSpan(
text: 'This will remove the server ',
),
TextSpan( TextSpan(
text: server.serverUrl.host, text: server.serverUrl.host,
style: TextStyle( style: TextStyle(
@ -173,8 +194,13 @@ class DeleteServerTile extends HookConsumerWidget {
TextButton( TextButton(
onPressed: () { onPressed: () {
ref ref
.read(audiobookShelfServerProvider.notifier) .read(
.removeServer(server, removeUsers: true); audiobookShelfServerProvider.notifier,
)
.removeServer(
server,
removeUsers: true,
);
Navigator.of(context).pop(); Navigator.of(context).pop();
}, },
child: const Text('Delete'), child: const Text('Delete'),
@ -189,7 +215,10 @@ class DeleteServerTile extends HookConsumerWidget {
} }
class AddUserTile extends HookConsumerWidget { class AddUserTile extends HookConsumerWidget {
const AddUserTile({super.key, required this.server}); const AddUserTile({
super.key,
required this.server,
});
final model.AudiobookShelfServer server; final model.AudiobookShelfServer server;
@ -223,12 +252,10 @@ class AddUserTile extends HookConsumerWidget {
label: 'Switch', label: 'Switch',
onPressed: () { onPressed: () {
// Switch to the new user // Switch to the new user
ref ref.read(apiSettingsProvider.notifier).updateState(
.read(apiSettingsProvider.notifier) ref.read(apiSettingsProvider).copyWith(
.updateState( activeUser: user,
ref ),
.read(apiSettingsProvider)
.copyWith(activeUser: user),
); );
context.goNamed(Routes.home.name); context.goNamed(Routes.home.name);
}, },
@ -256,7 +283,10 @@ class AddUserTile extends HookConsumerWidget {
} }
class AvailableUserTile extends HookConsumerWidget { class AvailableUserTile extends HookConsumerWidget {
const AvailableUserTile({super.key, required this.user}); const AvailableUserTile({
super.key,
required this.user,
});
final model.AuthenticatedUser user; final model.AuthenticatedUser user;
@ -273,14 +303,18 @@ class AvailableUserTile extends HookConsumerWidget {
onTap: apiSettings.activeUser == user onTap: apiSettings.activeUser == user
? null ? null
: () { : () {
ref ref.read(apiSettingsProvider.notifier).updateState(
.read(apiSettingsProvider.notifier) apiSettings.copyWith(
.updateState(apiSettings.copyWith(activeUser: user)); activeUser: user,
),
);
// pop all routes and go to the home page // pop all routes and go to the home page
// while (context.canPop()) { // while (context.canPop()) {
// context.pop(); // context.pop();
// } // }
context.goNamed(Routes.home.name); context.goNamed(
Routes.home.name,
);
}, },
trailing: IconButton( trailing: IconButton(
icon: const Icon(Icons.delete), icon: const Icon(Icons.delete),
@ -303,7 +337,9 @@ class AvailableUserTile extends HookConsumerWidget {
color: Theme.of(context).colorScheme.primary, color: Theme.of(context).colorScheme.primary,
), ),
), ),
const TextSpan(text: ' from this app.'), const TextSpan(
text: ' from this app.',
),
], ],
), ),
), ),
@ -317,7 +353,9 @@ class AvailableUserTile extends HookConsumerWidget {
TextButton( TextButton(
onPressed: () { onPressed: () {
ref ref
.read(authenticatedUsersProvider.notifier) .read(
authenticatedUsersProvider.notifier,
)
.removeUser(user); .removeUser(user);
Navigator.of(context).pop(); Navigator.of(context).pop();
}, },

View file

@ -11,7 +11,10 @@ import 'package:flutter/foundation.dart';
import 'package:vaani/main.dart' show appLogger; import 'package:vaani/main.dart' show appLogger;
class LibrarySwitchChip extends HookConsumerWidget { class LibrarySwitchChip extends HookConsumerWidget {
const LibrarySwitchChip({super.key, required this.libraries}); const LibrarySwitchChip({
super.key,
required this.libraries,
});
final List<Library> libraries; final List<Library> libraries;
@override @override
@ -23,7 +26,9 @@ class LibrarySwitchChip extends HookConsumerWidget {
AbsIcons.getIconByName( AbsIcons.getIconByName(
apiSettings.activeLibraryId != null apiSettings.activeLibraryId != null
? libraries ? libraries
.firstWhere((lib) => lib.id == apiSettings.activeLibraryId) .firstWhere(
(lib) => lib.id == apiSettings.activeLibraryId,
)
.icon .icon
: libraries.first.icon, : libraries.first.icon,
), ),
@ -31,14 +36,20 @@ class LibrarySwitchChip extends HookConsumerWidget {
label: const Text('Change Library'), label: const Text('Change Library'),
// Enable only if libraries are loaded and not empty // Enable only if libraries are loaded and not empty
onPressed: libraries.isNotEmpty onPressed: libraries.isNotEmpty
? () => showLibrarySwitcher(context, ref) ? () => showLibrarySwitcher(
context,
ref,
)
: null, // Disable if no libraries : null, // Disable if no libraries
); );
} }
} }
// --- Helper Function to Show the Switcher --- // --- Helper Function to Show the Switcher ---
void showLibrarySwitcher(BuildContext context, WidgetRef ref) { void showLibrarySwitcher(
BuildContext context,
WidgetRef ref,
) {
final content = _LibrarySelectionContent(); final content = _LibrarySelectionContent();
// --- Platform-Specific UI --- // --- Platform-Specific UI ---
@ -198,9 +209,7 @@ class _LibrarySelectionContent extends ConsumerWidget {
// Get current settings state // Get current settings state
final currentSettings = ref.read(apiSettingsProvider); final currentSettings = ref.read(apiSettingsProvider);
// Update the active library ID // Update the active library ID
ref ref.read(apiSettingsProvider.notifier).updateState(
.read(apiSettingsProvider.notifier)
.updateState(
currentSettings.copyWith(activeLibraryId: library.id), currentSettings.copyWith(activeLibraryId: library.id),
); );
// Close the dialog/bottom sheet // Close the dialog/bottom sheet

View file

@ -12,7 +12,9 @@ import 'package:vaani/shared/widgets/not_implemented.dart';
import 'package:vaani/shared/widgets/vaani_logo.dart'; import 'package:vaani/shared/widgets/vaani_logo.dart';
class YouPage extends HookConsumerWidget { class YouPage extends HookConsumerWidget {
const YouPage({super.key}); const YouPage({
super.key,
});
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
@ -86,9 +88,8 @@ class YouPage extends HookConsumerWidget {
// Maybe show error details or allow retry // Maybe show error details or allow retry
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
SnackBar( SnackBar(
content: Text( content:
'Failed to load libraries: $error', Text('Failed to load libraries: $error'),
),
), ),
); );
}, },
@ -158,7 +159,9 @@ class YouPage extends HookConsumerWidget {
Theme.of(context).colorScheme.primary, Theme.of(context).colorScheme.primary,
BlendMode.srcIn, BlendMode.srcIn,
), ),
child: const VaaniLogo(size: 48), child: const VaaniLogo(
size: 48,
),
), ),
), ),
], ],
@ -173,7 +176,9 @@ class YouPage extends HookConsumerWidget {
} }
class UserBar extends HookConsumerWidget { class UserBar extends HookConsumerWidget {
const UserBar({super.key}); const UserBar({
super.key,
});
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
@ -212,9 +217,8 @@ class UserBar extends HookConsumerWidget {
Text( Text(
api.baseUrl.toString(), api.baseUrl.toString(),
style: textTheme.bodyMedium?.copyWith( style: textTheme.bodyMedium?.copyWith(
color: themeData.colorScheme.onSurface.withValues( color:
alpha: 0.6, themeData.colorScheme.onSurface.withValues(alpha: 0.6),
),
), ),
), ),
], ],

View file

@ -14,7 +14,10 @@ import 'package:flutter/material.dart';
class InactiveFocusScopeObserver extends StatefulWidget { class InactiveFocusScopeObserver extends StatefulWidget {
final Widget child; final Widget child;
const InactiveFocusScopeObserver({super.key, required this.child}); const InactiveFocusScopeObserver({
super.key,
required this.child,
});
@override @override
State<InactiveFocusScopeObserver> createState() => State<InactiveFocusScopeObserver> createState() =>
@ -36,8 +39,10 @@ class _InactiveFocusScopeObserverState
} }
@override @override
Widget build(BuildContext context) => Widget build(BuildContext context) => FocusScope(
FocusScope(node: _focusScope, child: widget.child); node: _focusScope,
child: widget.child,
);
@override @override
void dispose() { void dispose() {

View file

@ -33,7 +33,11 @@ void main() async {
await configurePlayer(); await configurePlayer();
// run the app // run the app
runApp(const ProviderScope(child: _EagerInitialization(child: MyApp()))); runApp(
const ProviderScope(
child: _EagerInitialization(child: MyApp()),
),
);
} }
var routerConfig = const MyAppRouter().config; var routerConfig = const MyAppRouter().config;
@ -61,17 +65,20 @@ class MyApp extends ConsumerWidget {
themeSettings.highContrast || MediaQuery.of(context).highContrast; themeSettings.highContrast || MediaQuery.of(context).highContrast;
if (shouldUseHighContrast) { if (shouldUseHighContrast) {
lightColorScheme = lightColorScheme.copyWith(surface: Colors.white); lightColorScheme = lightColorScheme.copyWith(
darkColorScheme = darkColorScheme.copyWith(surface: Colors.black); surface: Colors.white,
);
darkColorScheme = darkColorScheme.copyWith(
surface: Colors.black,
);
} }
if (themeSettings.useMaterialThemeFromSystem) { if (themeSettings.useMaterialThemeFromSystem) {
var themes = ref.watch( var themes =
systemThemeProvider(highContrast: shouldUseHighContrast), ref.watch(systemThemeProvider(highContrast: shouldUseHighContrast));
); if (themes.valueOrNull != null) {
if (themes.value != null) { lightColorScheme = themes.valueOrNull!.$1;
lightColorScheme = themes.value!.$1; darkColorScheme = themes.valueOrNull!.$2;
darkColorScheme = themes.value!.$2;
} }
} }
@ -93,9 +100,9 @@ class MyApp extends ConsumerWidget {
brightness: Brightness.dark, brightness: Brightness.dark,
), ),
); );
if (themeLight.value != null && themeDark.value != null) { if (themeLight.valueOrNull != null && themeDark.valueOrNull != null) {
lightColorScheme = themeLight.value!; lightColorScheme = themeLight.valueOrNull!;
darkColorScheme = themeDark.value!; darkColorScheme = themeDark.valueOrNull!;
} }
} }
} catch (e) { } catch (e) {

View file

@ -52,9 +52,7 @@ class HomePage extends HookConsumerWidget {
// try again button // try again button
ElevatedButton( ElevatedButton(
onPressed: () { onPressed: () {
ref ref.read(apiSettingsProvider.notifier).updateState(
.read(apiSettingsProvider.notifier)
.updateState(
apiSettings.copyWith(activeLibraryId: null), apiSettings.copyWith(activeLibraryId: null),
); );
ref.invalidate(personalizedViewProvider); ref.invalidate(personalizedViewProvider);
@ -85,8 +83,7 @@ class HomePage extends HookConsumerWidget {
shelf: shelf, shelf: shelf,
showPlayButton: showPlayButton, showPlayButton: showPlayButton,
); );
}) }).toList();
.toList();
return RefreshIndicator( return RefreshIndicator(
onRefresh: () async { onRefresh: () async {
return ref.refresh(personalizedViewProvider); return ref.refresh(personalizedViewProvider);
@ -135,6 +132,10 @@ class HomePageSkeleton extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return const Scaffold(body: Center(child: CircularProgressIndicator())); return const Scaffold(
body: Center(
child: CircularProgressIndicator(),
),
);
} }
} }

View file

@ -17,9 +17,7 @@ class LibraryPage extends HookConsumerWidget {
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
// set the library id as the active library // set the library id as the active library
if (libraryId != null) { if (libraryId != null) {
ref ref.read(apiSettingsProvider.notifier).updateState(
.read(apiSettingsProvider.notifier)
.updateState(
ref.watch(apiSettingsProvider).copyWith(activeLibraryId: libraryId), ref.watch(apiSettingsProvider).copyWith(activeLibraryId: libraryId),
); );
} }
@ -51,9 +49,11 @@ class LibraryPage extends HookConsumerWidget {
// .where((element) => !element.id.contains('discover')) // .where((element) => !element.id.contains('discover'))
.map((shelf) { .map((shelf) {
appLogger.fine('building shelf ${shelf.label}'); appLogger.fine('building shelf ${shelf.label}');
return HomeShelf(title: shelf.label, shelf: shelf); return HomeShelf(
}) title: shelf.label,
.toList(); shelf: shelf,
);
}).toList();
return RefreshIndicator( return RefreshIndicator(
onRefresh: () async { onRefresh: () async {
return ref.refresh(personalizedViewProvider); return ref.refresh(personalizedViewProvider);
@ -85,6 +85,10 @@ class LibraryPageSkeleton extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return const Scaffold(body: Center(child: CircularProgressIndicator())); return const Scaffold(
body: Center(
child: CircularProgressIndicator(),
),
);
} }
} }

View file

@ -3,8 +3,14 @@
part of 'router.dart'; part of 'router.dart';
class Routes { class Routes {
static const home = _SimpleRoute(pathName: '', name: 'home'); static const home = _SimpleRoute(
static const onboarding = _SimpleRoute(pathName: 'login', name: 'onboarding'); pathName: '',
name: 'home',
);
static const onboarding = _SimpleRoute(
pathName: 'login',
name: 'onboarding',
);
static const library = _SimpleRoute( static const library = _SimpleRoute(
pathName: 'library', pathName: 'library',
pathParamName: 'libraryId', pathParamName: 'libraryId',
@ -17,7 +23,10 @@ class Routes {
); );
// Local settings // Local settings
static const settings = _SimpleRoute(pathName: 'config', name: 'settings'); static const settings = _SimpleRoute(
pathName: 'config',
name: 'settings',
);
static const themeSettings = _SimpleRoute( static const themeSettings = _SimpleRoute(
pathName: 'theme', pathName: 'theme',
name: 'themeSettings', name: 'themeSettings',
@ -55,7 +64,10 @@ class Routes {
name: 'search', name: 'search',
// parentRoute: library, // parentRoute: library,
); );
static const explore = _SimpleRoute(pathName: 'explore', name: 'explore'); static const explore = _SimpleRoute(
pathName: 'explore',
name: 'explore',
);
// downloads // downloads
static const downloads = _SimpleRoute( static const downloads = _SimpleRoute(
@ -71,7 +83,10 @@ class Routes {
); );
// you page for the user // you page for the user
static const you = _SimpleRoute(pathName: 'you', name: 'you'); static const you = _SimpleRoute(
pathName: 'you',
name: 'you',
);
// user management // user management
static const userManagement = _SimpleRoute( static const userManagement = _SimpleRoute(
@ -87,7 +102,10 @@ class Routes {
); );
// logs page // logs page
static const logs = _SimpleRoute(pathName: 'logs', name: 'logs'); static const logs = _SimpleRoute(
pathName: 'logs',
name: 'logs',
);
} }
// a class to store path // a class to store path

View file

@ -11,7 +11,7 @@ part 'library_item_extras.freezed.dart';
/// [book] is the book that the item represents /// [book] is the book that the item represents
/// [heroTagSuffix] is the suffix to use for the hero tag to avoid conflicts /// [heroTagSuffix] is the suffix to use for the hero tag to avoid conflicts
@freezed @freezed
sealed class LibraryItemExtras with _$LibraryItemExtras { class LibraryItemExtras with _$LibraryItemExtras {
const factory LibraryItemExtras({ const factory LibraryItemExtras({
BookMinified? book, BookMinified? book,
@Default('') String heroTagSuffix, @Default('') String heroTagSuffix,

View file

@ -1,5 +1,5 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
// coverage:ignore-file // coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint // 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 // 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,260 +9,156 @@ part of 'library_item_extras.dart';
// FreezedGenerator // FreezedGenerator
// ************************************************************************** // **************************************************************************
// dart format off
T _$identity<T>(T value) => value; 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 /// @nodoc
mixin _$LibraryItemExtras { mixin _$LibraryItemExtras {
BookMinified? get book => throw _privateConstructorUsedError;
String get heroTagSuffix => throw _privateConstructorUsedError;
BookMinified? get book; String get heroTagSuffix; /// Create a copy of LibraryItemExtras
/// Create a copy of LibraryItemExtras /// with the given fields replaced by the non-null parameter values.
/// with the given fields replaced by the non-null parameter values. @JsonKey(includeFromJson: false, includeToJson: false)
@JsonKey(includeFromJson: false, includeToJson: false) $LibraryItemExtrasCopyWith<LibraryItemExtras> get copyWith =>
@pragma('vm:prefer-inline') throw _privateConstructorUsedError;
$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 /// @nodoc
abstract mixin class $LibraryItemExtrasCopyWith<$Res> { abstract class $LibraryItemExtrasCopyWith<$Res> {
factory $LibraryItemExtrasCopyWith(LibraryItemExtras value, $Res Function(LibraryItemExtras) _then) = _$LibraryItemExtrasCopyWithImpl; factory $LibraryItemExtrasCopyWith(
@useResult LibraryItemExtras value, $Res Function(LibraryItemExtras) then) =
$Res call({ _$LibraryItemExtrasCopyWithImpl<$Res, LibraryItemExtras>;
BookMinified? book, String heroTagSuffix @useResult
}); $Res call({BookMinified? book, String heroTagSuffix});
} }
/// @nodoc /// @nodoc
class _$LibraryItemExtrasCopyWithImpl<$Res> class _$LibraryItemExtrasCopyWithImpl<$Res, $Val extends LibraryItemExtras>
implements $LibraryItemExtrasCopyWith<$Res> { implements $LibraryItemExtrasCopyWith<$Res> {
_$LibraryItemExtrasCopyWithImpl(this._self, this._then); _$LibraryItemExtrasCopyWithImpl(this._value, this._then);
final LibraryItemExtras _self; // ignore: unused_field
final $Res Function(LibraryItemExtras) _then; final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of LibraryItemExtras /// Create a copy of LibraryItemExtras
/// with the given fields replaced by the non-null parameter values. /// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') @override $Res call({Object? book = freezed,Object? heroTagSuffix = null,}) { @pragma('vm:prefer-inline')
return _then(_self.copyWith( @override
book: freezed == book ? _self.book : book // ignore: cast_nullable_to_non_nullable $Res call({
as BookMinified?,heroTagSuffix: null == heroTagSuffix ? _self.heroTagSuffix : heroTagSuffix // ignore: cast_nullable_to_non_nullable Object? book = freezed,
as String, 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);
}
}
/// @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 /// @nodoc
class _$LibraryItemExtrasImpl implements _LibraryItemExtras {
const _$LibraryItemExtrasImpl({this.book, this.heroTagSuffix = ''});
class _LibraryItemExtras implements LibraryItemExtras { @override
const _LibraryItemExtras({this.book, this.heroTagSuffix = ''}); final BookMinified? book;
@override
@JsonKey()
final String heroTagSuffix;
@override
@override final BookMinified? book; String toString() {
@override@JsonKey() final String 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
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)'; return 'LibraryItemExtras(book: $book, heroTagSuffix: $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));
}
@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);
} }
abstract class _LibraryItemExtras implements LibraryItemExtras {
const factory _LibraryItemExtras(
{final BookMinified? book,
final String heroTagSuffix}) = _$LibraryItemExtrasImpl;
@override
BookMinified? get book;
@override
String get 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;
} }
/// @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

View file

@ -25,9 +25,8 @@ import 'transitions/slide.dart';
part 'constants.dart'; part 'constants.dart';
final GlobalKey<NavigatorState> rootNavigatorKey = GlobalKey<NavigatorState>( final GlobalKey<NavigatorState> rootNavigatorKey =
debugLabel: 'root', GlobalKey<NavigatorState>(debugLabel: 'root');
);
final GlobalKey<NavigatorState> sectionHomeNavigatorKey = final GlobalKey<NavigatorState> sectionHomeNavigatorKey =
GlobalKey<NavigatorState>(debugLabel: 'HomeNavigator'); GlobalKey<NavigatorState>(debugLabel: 'HomeNavigator');
@ -63,8 +62,7 @@ class MyAppRouter {
), ),
// The main app shell // The main app shell
StatefulShellRoute.indexedStack( StatefulShellRoute.indexedStack(
builder: builder: (
(
BuildContext context, BuildContext context,
GoRouterState state, GoRouterState state,
StatefulNavigationShell navigationShell, StatefulNavigationShell navigationShell,
@ -96,12 +94,10 @@ class MyAppRouter {
// itemId: itemId, extra: state.extra); // itemId: itemId, extra: state.extra);
// }, // },
pageBuilder: (context, state) { pageBuilder: (context, state) {
final itemId = final itemId = state
state.pathParameters[Routes.libraryItem.pathParamName]!; .pathParameters[Routes.libraryItem.pathParamName]!;
final child = LibraryItemPage( final child =
itemId: itemId, LibraryItemPage(itemId: itemId, extra: state.extra);
extra: state.extra,
);
return buildPageWithDefaultTransition( return buildPageWithDefaultTransition(
context: context, context: context,
state: state, state: state,
@ -187,7 +183,9 @@ class MyAppRouter {
GoRoute( GoRoute(
path: Routes.themeSettings.pathName, path: Routes.themeSettings.pathName,
name: Routes.themeSettings.name, name: Routes.themeSettings.name,
pageBuilder: defaultPageBuilder(const ThemeSettingsPage()), pageBuilder: defaultPageBuilder(
const ThemeSettingsPage(),
),
), ),
GoRoute( GoRoute(
path: Routes.autoSleepTimerSettings.pathName, path: Routes.autoSleepTimerSettings.pathName,
@ -206,7 +204,8 @@ class MyAppRouter {
GoRoute( GoRoute(
path: Routes.playerSettings.pathName, path: Routes.playerSettings.pathName,
name: Routes.playerSettings.name, name: Routes.playerSettings.name,
pageBuilder: defaultPageBuilder(const PlayerSettingsPage()), pageBuilder:
defaultPageBuilder(const PlayerSettingsPage()),
), ),
GoRoute( GoRoute(
path: Routes.shakeDetectorSettings.pathName, path: Routes.shakeDetectorSettings.pathName,
@ -245,17 +244,17 @@ class MyAppRouter {
], ],
); );
Page handleCallback(BuildContext context, GoRouterState state) { Page handleCallback(
BuildContext context,
GoRouterState state,
) {
// extract the code and state from the uri // extract the code and state from the uri
final code = state.uri.queryParameters['code']; final code = state.uri.queryParameters['code'];
final stateParam = state.uri.queryParameters['state']; final stateParam = state.uri.queryParameters['state'];
appLogger.fine('deep linking callback: code: $code, state: $stateParam'); appLogger.fine('deep linking callback: code: $code, state: $stateParam');
var callbackPage = CallbackPage( var callbackPage =
code: code, CallbackPage(code: code, state: stateParam, key: ValueKey(stateParam));
state: stateParam,
key: ValueKey(stateParam),
);
return buildPageWithDefaultTransition( return buildPageWithDefaultTransition(
context: context, context: context,
state: state, state: state,

View file

@ -23,8 +23,10 @@ const bottomBarHeight = 64;
/// BottomNavigationBar, where [child] is placed in the body of the Scaffold. /// BottomNavigationBar, where [child] is placed in the body of the Scaffold.
class ScaffoldWithNavBar extends HookConsumerWidget { class ScaffoldWithNavBar extends HookConsumerWidget {
/// Constructs an [ScaffoldWithNavBar]. /// Constructs an [ScaffoldWithNavBar].
const ScaffoldWithNavBar({required this.navigationShell, Key? key}) const ScaffoldWithNavBar({
: super(key: key ?? const ValueKey<String>('ScaffoldWithNavBar')); required this.navigationShell,
Key? key,
}) : super(key: key ?? const ValueKey<String>('ScaffoldWithNavBar'));
/// The navigation shell and container for the branch Navigators. /// The navigation shell and container for the branch Navigators.
final StatefulNavigationShell navigationShell; final StatefulNavigationShell navigationShell;
@ -33,11 +35,10 @@ class ScaffoldWithNavBar extends HookConsumerWidget {
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
// playerExpandProgress is used to animate bottom navigation bar to opacity 0 and slide down when player is expanded // playerExpandProgress is used to animate bottom navigation bar to opacity 0 and slide down when player is expanded
// final playerProgress = // final playerProgress =
// useValueListenable(ref.watch(playerExpandProgressProvider)); // useValueListenable(ref.watch(playerExpandProgressNotifierProvider));
final playerProgress = ref.watch(playerHeightProvider); final playerProgress = ref.watch(playerHeightProvider);
final playerMaxHeight = MediaQuery.of(context).size.height; final playerMaxHeight = MediaQuery.of(context).size.height;
var percentExpandedMiniPlayer = var percentExpandedMiniPlayer = (playerProgress - playerMinHeight) /
(playerProgress - playerMinHeight) /
(playerMaxHeight - playerMinHeight); (playerMaxHeight - playerMinHeight);
// Clamp the value between 0 and 1 // Clamp the value between 0 and 1
percentExpandedMiniPlayer = percentExpandedMiniPlayer.clamp(0.0, 1.0); percentExpandedMiniPlayer = percentExpandedMiniPlayer.clamp(0.0, 1.0);
@ -51,7 +52,9 @@ class ScaffoldWithNavBar extends HookConsumerWidget {
// close miniplayer if it is open // close miniplayer if it is open
if (isPlayerExpanded && pendingPlayerModals == 0) { if (isPlayerExpanded && pendingPlayerModals == 0) {
appLogger.fine('BackButtonListener: closing the player'); appLogger.fine(
'BackButtonListener: closing the player',
);
audioBookMiniplayerController.animateToHeight(state: PanelState.MIN); audioBookMiniplayerController.animateToHeight(state: PanelState.MIN);
return true; return true;
} }
@ -93,7 +96,12 @@ class ScaffoldWithNavBar extends HookConsumerWidget {
return BackButtonListener( return BackButtonListener(
onBackButtonPressed: onBackButtonPressed, onBackButtonPressed: onBackButtonPressed,
child: Scaffold( child: Scaffold(
body: Stack(children: [navigationShell, const AudiobookPlayer()]), body: Stack(
children: [
navigationShell,
const AudiobookPlayer(),
],
),
bottomNavigationBar: Opacity( bottomNavigationBar: Opacity(
// Opacity is interpolated from 1 to 0 when player is expanded // Opacity is interpolated from 1 to 0 when player is expanded
opacity: 1 - percentExpandedMiniPlayer, opacity: 1 - percentExpandedMiniPlayer,
@ -108,8 +116,11 @@ class ScaffoldWithNavBar extends HookConsumerWidget {
// `navigationShell.route.branches`. // `navigationShell.route.branches`.
destinations: _navigationItems.map((item) { destinations: _navigationItems.map((item) {
final isDestinationLibrary = item.name == 'Library'; final isDestinationLibrary = item.name == 'Library';
var currentLibrary = ref.watch(currentLibraryProvider).value; var currentLibrary =
final libraryIcon = AbsIcons.getIconByName(currentLibrary?.icon); ref.watch(currentLibraryProvider).valueOrNull;
final libraryIcon = AbsIcons.getIconByName(
currentLibrary?.icon,
);
final destinationWidget = NavigationDestination( final destinationWidget = NavigationDestination(
icon: Icon( icon: Icon(
isDestinationLibrary ? libraryIcon ?? item.icon : item.icon, isDestinationLibrary ? libraryIcon ?? item.icon : item.icon,

View file

@ -39,7 +39,9 @@ CustomTransitionPage buildPageWithDefaultTransition<T>({
Tween( Tween(
begin: const Offset(0, 1.50), begin: const Offset(0, 1.50),
end: Offset.zero, end: Offset.zero,
).chain(CurveTween(curve: Curves.easeOut)), ).chain(
CurveTween(curve: Curves.easeOut),
),
), ),
child: child, child: child,
), ),
@ -49,10 +51,11 @@ CustomTransitionPage buildPageWithDefaultTransition<T>({
Page<dynamic> Function(BuildContext, GoRouterState) defaultPageBuilder<T>( Page<dynamic> Function(BuildContext, GoRouterState) defaultPageBuilder<T>(
Widget child, Widget child,
) => (BuildContext context, GoRouterState state) { ) =>
(BuildContext context, GoRouterState state) {
return buildPageWithDefaultTransition<T>( return buildPageWithDefaultTransition<T>(
context: context, context: context,
state: state, state: state,
child: child, child: child,
); );
}; };

View file

@ -17,7 +17,7 @@ class ApiSettings extends _$ApiSettings {
@override @override
model.ApiSettings build() { model.ApiSettings build() {
state = readFromBoxOrCreate(); state = readFromBoxOrCreate();
listenSelf((_, __) { ref.listenSelf((_, __) {
writeToBox(); writeToBox();
}); });

View file

@ -6,57 +6,20 @@ part of 'api_settings_provider.dart';
// RiverpodGenerator // RiverpodGenerator
// ************************************************************************** // **************************************************************************
// GENERATED CODE - DO NOT MODIFY BY HAND String _$apiSettingsHash() => r'5bc1e16e9d72b77fb10637aabadf08e8947da580';
// ignore_for_file: type=lint, type=warning
/// See also [ApiSettings].
@ProviderFor(ApiSettings) @ProviderFor(ApiSettings)
final apiSettingsProvider = ApiSettingsProvider._(); final apiSettingsProvider =
NotifierProvider<ApiSettings, model.ApiSettings>.internal(
final class ApiSettingsProvider ApiSettings.new,
extends $NotifierProvider<ApiSettings, model.ApiSettings> {
ApiSettingsProvider._()
: super(
from: null,
argument: null,
retry: null,
name: r'apiSettingsProvider', name: r'apiSettingsProvider',
isAutoDispose: false, debugGetCreateSourceHash:
const bool.fromEnvironment('dart.vm.product') ? null : _$apiSettingsHash,
dependencies: null, dependencies: null,
$allTransitiveDependencies: null, allTransitiveDependencies: null,
); );
@override typedef _$ApiSettings = Notifier<model.ApiSettings>;
String debugGetCreateSourceHash() => _$apiSettingsHash(); // 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
@$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);
}
}

View file

@ -19,10 +19,8 @@ model.AppSettings loadOrCreateAppSettings() {
settings = _box.getAt(0); settings = _box.getAt(0);
_logger.fine('found settings in box: $settings'); _logger.fine('found settings in box: $settings');
} catch (e) { } catch (e) {
_logger.warning( _logger.warning('error reading settings from box: $e'
'error reading settings from box: $e' '\nclearing box');
'\nclearing box',
);
_box.clear(); _box.clear();
} }
} else { } else {
@ -36,7 +34,7 @@ class AppSettings extends _$AppSettings {
@override @override
model.AppSettings build() { model.AppSettings build() {
state = loadOrCreateAppSettings(); state = loadOrCreateAppSettings();
listenSelf((_, __) { ref.listenSelf((_, __) {
writeToBox(); writeToBox();
}); });
return state; return state;

View file

@ -6,112 +6,37 @@ part of 'app_settings_provider.dart';
// RiverpodGenerator // RiverpodGenerator
// ************************************************************************** // **************************************************************************
// GENERATED CODE - DO NOT MODIFY BY HAND String _$appSettingsHash() => r'314d7936f54550f57d308056a99230402342a6d0';
// ignore_for_file: type=lint, type=warning
/// See also [AppSettings].
@ProviderFor(AppSettings) @ProviderFor(AppSettings)
final appSettingsProvider = AppSettingsProvider._(); final appSettingsProvider =
NotifierProvider<AppSettings, model.AppSettings>.internal(
final class AppSettingsProvider AppSettings.new,
extends $NotifierProvider<AppSettings, model.AppSettings> {
AppSettingsProvider._()
: super(
from: null,
argument: null,
retry: null,
name: r'appSettingsProvider', name: r'appSettingsProvider',
isAutoDispose: false, debugGetCreateSourceHash:
const bool.fromEnvironment('dart.vm.product') ? null : _$appSettingsHash,
dependencies: null, dependencies: null,
$allTransitiveDependencies: null, allTransitiveDependencies: null,
); );
@override
String debugGetCreateSourceHash() => _$appSettingsHash();
@$internal
@override
AppSettings create() => AppSettings();
/// {@macro riverpod.override_with_value}
Override overrideWithValue(model.AppSettings value) {
return $ProviderOverride(
origin: this,
providerOverride: $SyncValueProvider<model.AppSettings>(value),
);
}
}
String _$appSettingsHash() => r'744d7e0157eb3b089c4187b35b845fc78547a44e';
abstract class _$AppSettings extends $Notifier<model.AppSettings> {
model.AppSettings build();
@$mustCallSuper
@override
void runBuild() {
final ref = this.ref as $Ref<model.AppSettings, model.AppSettings>;
final element =
ref.element
as $ClassProviderElement<
AnyNotifier<model.AppSettings, model.AppSettings>,
model.AppSettings,
Object?,
Object?
>;
element.handleCreate(ref, build);
}
}
@ProviderFor(SleepTimerSettings)
final sleepTimerSettingsProvider = SleepTimerSettingsProvider._();
final class SleepTimerSettingsProvider
extends $NotifierProvider<SleepTimerSettings, model.SleepTimerSettings> {
SleepTimerSettingsProvider._()
: super(
from: null,
argument: null,
retry: null,
name: r'sleepTimerSettingsProvider',
isAutoDispose: false,
dependencies: null,
$allTransitiveDependencies: null,
);
@override
String debugGetCreateSourceHash() => _$sleepTimerSettingsHash();
@$internal
@override
SleepTimerSettings create() => SleepTimerSettings();
/// {@macro riverpod.override_with_value}
Override overrideWithValue(model.SleepTimerSettings value) {
return $ProviderOverride(
origin: this,
providerOverride: $SyncValueProvider<model.SleepTimerSettings>(value),
);
}
}
typedef _$AppSettings = Notifier<model.AppSettings>;
String _$sleepTimerSettingsHash() => String _$sleepTimerSettingsHash() =>
r'85bb3d3fb292b9a3a5b771d86e5fc57718519c69'; r'85bb3d3fb292b9a3a5b771d86e5fc57718519c69';
abstract class _$SleepTimerSettings /// See also [SleepTimerSettings].
extends $Notifier<model.SleepTimerSettings> { @ProviderFor(SleepTimerSettings)
model.SleepTimerSettings build(); final sleepTimerSettingsProvider =
@$mustCallSuper NotifierProvider<SleepTimerSettings, model.SleepTimerSettings>.internal(
@override SleepTimerSettings.new,
void runBuild() { name: r'sleepTimerSettingsProvider',
final ref = debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
this.ref as $Ref<model.SleepTimerSettings, model.SleepTimerSettings>; ? null
final element = : _$sleepTimerSettingsHash,
ref.element dependencies: null,
as $ClassProviderElement< allTransitiveDependencies: null,
AnyNotifier<model.SleepTimerSettings, model.SleepTimerSettings>, );
model.SleepTimerSettings,
Object?, typedef _$SleepTimerSettings = Notifier<model.SleepTimerSettings>;
Object? // 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
element.handleCreate(ref, build);
}
}

Some files were not shown because too many files have changed in this diff Show more