diff --git a/lib/api/library_provider.dart b/lib/api/library_provider.dart deleted file mode 100644 index a138a7a..0000000 --- a/lib/api/library_provider.dart +++ /dev/null @@ -1,42 +0,0 @@ -import 'package:hooks_riverpod/hooks_riverpod.dart' show Ref; -import 'package:logging/logging.dart' show Logger; -import 'package:riverpod_annotation/riverpod_annotation.dart'; - -import 'package:shelfsdk/audiobookshelf_api.dart' show Library; -import 'package:vaani/api/api_provider.dart' show authenticatedApiProvider; -part 'library_provider.g.dart'; - -final _logger = Logger('LibraryProvider'); - -@riverpod -Future currentLibrary(Ref ref, String id) async { - final api = ref.watch(authenticatedApiProvider); - final library = await api.libraries.get(libraryId: id); - if (library == null) { - _logger.warning('No library found through id: $id'); - // try to get the library from the list of libraries - final libraries = await ref.watch(librariesProvider.future); - for (final lib in libraries) { - if (lib.id == id) { - return lib; - } - } - _logger.warning('No library found in the list of libraries'); - return null; - } - return library.library; -} - -@riverpod -class Libraries extends _$Libraries { - @override - FutureOr> build() async { - final api = ref.watch(authenticatedApiProvider); - final libraries = await api.libraries.getAll(); - if (libraries == null) { - _logger.warning('Failed to fetch libraries'); - return []; - } - return libraries; - } -} diff --git a/lib/api/library_provider.g.dart b/lib/api/library_provider.g.dart deleted file mode 100644 index 3161d34..0000000 --- a/lib/api/library_provider.g.dart +++ /dev/null @@ -1,176 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'library_provider.dart'; - -// ************************************************************************** -// RiverpodGenerator -// ************************************************************************** - -String _$currentLibraryHash() => r'f37904b8b43c88a523696d1ed7acf871c3e3326f'; - -/// Copied from Dart SDK -class _SystemHash { - _SystemHash._(); - - static int combine(int hash, int value) { - // ignore: parameter_assignments - hash = 0x1fffffff & (hash + value); - // ignore: parameter_assignments - hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10)); - return hash ^ (hash >> 6); - } - - static int finish(int hash) { - // ignore: parameter_assignments - hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3)); - // ignore: parameter_assignments - hash = hash ^ (hash >> 11); - return 0x1fffffff & (hash + ((0x00003fff & hash) << 15)); - } -} - -/// See also [currentLibrary]. -@ProviderFor(currentLibrary) -const currentLibraryProvider = CurrentLibraryFamily(); - -/// See also [currentLibrary]. -class CurrentLibraryFamily extends Family> { - /// See also [currentLibrary]. - const CurrentLibraryFamily(); - - /// See also [currentLibrary]. - CurrentLibraryProvider call( - String id, - ) { - return CurrentLibraryProvider( - id, - ); - } - - @override - CurrentLibraryProvider getProviderOverride( - covariant CurrentLibraryProvider provider, - ) { - return call( - provider.id, - ); - } - - static const Iterable? _dependencies = null; - - @override - Iterable? get dependencies => _dependencies; - - static const Iterable? _allTransitiveDependencies = null; - - @override - Iterable? get allTransitiveDependencies => - _allTransitiveDependencies; - - @override - String? get name => r'currentLibraryProvider'; -} - -/// See also [currentLibrary]. -class CurrentLibraryProvider extends AutoDisposeFutureProvider { - /// See also [currentLibrary]. - CurrentLibraryProvider( - String id, - ) : this._internal( - (ref) => currentLibrary( - ref as CurrentLibraryRef, - id, - ), - from: currentLibraryProvider, - name: r'currentLibraryProvider', - debugGetCreateSourceHash: - const bool.fromEnvironment('dart.vm.product') - ? null - : _$currentLibraryHash, - dependencies: CurrentLibraryFamily._dependencies, - allTransitiveDependencies: - CurrentLibraryFamily._allTransitiveDependencies, - id: id, - ); - - CurrentLibraryProvider._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 Function(CurrentLibraryRef provider) create, - ) { - return ProviderOverride( - origin: this, - override: CurrentLibraryProvider._internal( - (ref) => create(ref as CurrentLibraryRef), - from: from, - name: null, - dependencies: null, - allTransitiveDependencies: null, - debugGetCreateSourceHash: null, - id: id, - ), - ); - } - - @override - AutoDisposeFutureProviderElement createElement() { - return _CurrentLibraryProviderElement(this); - } - - @override - bool operator ==(Object other) { - return other is CurrentLibraryProvider && other.id == id; - } - - @override - int get hashCode { - var hash = _SystemHash.combine(0, runtimeType.hashCode); - hash = _SystemHash.combine(hash, id.hashCode); - - return _SystemHash.finish(hash); - } -} - -@Deprecated('Will be removed in 3.0. Use Ref instead') -// ignore: unused_element -mixin CurrentLibraryRef on AutoDisposeFutureProviderRef { - /// The parameter `id` of this provider. - String get id; -} - -class _CurrentLibraryProviderElement - extends AutoDisposeFutureProviderElement with CurrentLibraryRef { - _CurrentLibraryProviderElement(super.provider); - - @override - String get id => (origin as CurrentLibraryProvider).id; -} - -String _$librariesHash() => r'a79954d0b68a8265859c577e36d5596620a72843'; - -/// See also [Libraries]. -@ProviderFor(Libraries) -final librariesProvider = - AutoDisposeAsyncNotifierProvider>.internal( - Libraries.new, - name: r'librariesProvider', - debugGetCreateSourceHash: - const bool.fromEnvironment('dart.vm.product') ? null : _$librariesHash, - dependencies: null, - allTransitiveDependencies: null, -); - -typedef _$Libraries = AutoDisposeAsyncNotifier>; -// 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 diff --git a/lib/features/logging/view/logs_page.dart b/lib/features/logging/view/logs_page.dart index b774963..ad2c764 100644 --- a/lib/features/logging/view/logs_page.dart +++ b/lib/features/logging/view/logs_page.dart @@ -1,11 +1,15 @@ +import 'dart:io'; +import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:logging/logging.dart'; +import 'package:permission_handler/permission_handler.dart'; import 'package:share_plus/share_plus.dart'; import 'package:vaani/features/logging/providers/logs_provider.dart'; import 'package:vaani/main.dart'; +import 'package:vaani/settings/metadata/metadata_provider.dart'; class LogsPage extends HookConsumerWidget { const LogsPage({super.key}); diff --git a/lib/features/you/view/you_page.dart b/lib/features/you/view/you_page.dart index 69eeecc..c15e80f 100644 --- a/lib/features/you/view/you_page.dart +++ b/lib/features/you/view/you_page.dart @@ -1,22 +1,12 @@ -import 'dart:io' show Platform; - -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:shelfsdk/audiobookshelf_api.dart' show Library; import 'package:vaani/api/api_provider.dart'; -import 'package:vaani/api/library_provider.dart' show librariesProvider; import 'package:vaani/features/player/view/mini_player_bottom_padding.dart'; -import 'package:vaani/main.dart' show appLogger; import 'package:vaani/router/router.dart'; -import 'package:vaani/settings/api_settings_provider.dart' - show apiSettingsProvider; import 'package:vaani/settings/constants.dart'; -import 'package:vaani/shared/icons/abs_icons.dart'; import 'package:vaani/shared/utils.dart'; import 'package:vaani/shared/widgets/not_implemented.dart'; -import 'package:vaani/shared/widgets/vaani_logo.dart'; class YouPage extends HookConsumerWidget { const YouPage({ @@ -26,9 +16,6 @@ class YouPage extends HookConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final api = ref.watch(authenticatedApiProvider); - final librariesAsyncValue = ref.watch(librariesProvider); - // Get current settings to know the active library ID later - final apiSettings = ref.watch(apiSettingsProvider); return Scaffold( appBar: AppBar( // title: const Text('You'), @@ -76,58 +63,7 @@ class YouPage extends HookConsumerWidget { context.pushNamed(Routes.userManagement.name); }, ), - librariesAsyncValue.when( - data: (libraries) => ActionChip( - avatar: Icon( - AbsIcons.getIconByName( - apiSettings.activeLibraryId != null - ? libraries - .firstWhere( - (lib) => - lib.id == - apiSettings.activeLibraryId, - ) - .icon - : libraries.first.icon, - ), - ), // Replace with your icon - label: const Text('Change Library'), - // Enable only if libraries are loaded and not empty - onPressed: libraries.isNotEmpty - ? () => _showLibrarySwitcher( - context, - ref, - libraries, - apiSettings.activeLibraryId, - ) - : null, // Disable if no libraries - ), - loading: () => const ActionChip( - avatar: SizedBox( - width: 18, - height: 18, - child: CircularProgressIndicator(strokeWidth: 2), - ), - label: Text('Loading Libs...'), - onPressed: null, // Disable while loading - ), - error: (error, stack) => ActionChip( - avatar: Icon( - Icons.error_outline, - color: Theme.of(context).colorScheme.error, - ), - label: const Text('Error Loading Libs'), - onPressed: () { - // Maybe show error details or allow retry - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: - Text('Failed to load libraries: $error'), - ), - ); - }, - ), - ), // ActionChip( + // ActionChip( // avatar: const Icon(Icons.logout), // label: const Text('Logout'), // onPressed: () { @@ -208,124 +144,6 @@ class YouPage extends HookConsumerWidget { } } -// --- Helper Function to Show the Switcher --- -void _showLibrarySwitcher( - BuildContext context, - WidgetRef ref, - List libraries, // Pass loaded libraries - String? currentLibraryId, // Pass current ID -) { - final content = _LibrarySelectionContent( - libraries: libraries, - currentLibraryId: currentLibraryId, - ); - - // --- Platform-Specific UI --- - bool isDesktop = false; - if (!kIsWeb) { - // dart:io Platform is not available on web - isDesktop = Platform.isLinux || Platform.isMacOS || Platform.isWindows; - } else { - // Basic web detection (might need refinement based on screen size) - // Consider using MediaQuery for a size-based check instead for web/tablet - final size = MediaQuery.of(context).size; - isDesktop = size.width > 600; // Example threshold for "desktop-like" layout - } - - if (isDesktop) { - // --- Desktop: Use AlertDialog --- - showDialog( - context: context, - builder: (dialogContext) => AlertDialog( - title: const Text('Select Library'), - content: SizedBox( - // Constrain size for dialogs - width: 300, // Adjust as needed - // Make content scrollable if list is long - child: Scrollbar(child: content), - ), - actions: [ - TextButton( - onPressed: () => Navigator.pop(dialogContext), - child: const Text('Cancel'), - ), - ], - ), - ); - } else { - // --- Mobile/Tablet: Use BottomSheet --- - showModalBottomSheet( - context: context, - // Make it scrollable and control height - isScrollControlled: true, - constraints: BoxConstraints( - maxHeight: - MediaQuery.of(context).size.height * 0.6, // Max 60% of screen - ), - builder: (sheetContext) => Padding( - // Add padding within the bottom sheet - padding: const EdgeInsets.all(16.0), - child: Column( - mainAxisSize: MainAxisSize.min, // Take minimum necessary height - children: [ - const Text( - 'Select Library', - style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), - ), - const SizedBox(height: 10), - const Divider(), - Flexible( - // Allow the list to take remaining space and scroll - child: Scrollbar(child: content), - ), - ], - ), - ), - ); - } -} - -// --- Widget for the Selection List Content (Reusable) --- -class _LibrarySelectionContent extends ConsumerWidget { - final List libraries; - final String? currentLibraryId; - - const _LibrarySelectionContent({ - required this.libraries, - this.currentLibraryId, - }); - - @override - Widget build(BuildContext context, WidgetRef ref) { - return ListView.builder( - shrinkWrap: true, // Important for Dialog/BottomSheet sizing - itemCount: libraries.length, - itemBuilder: (context, index) { - final library = libraries[index]; - final bool isSelected = library.id == currentLibraryId; - - return ListTile( - title: Text(library.name), - leading: Icon(AbsIcons.getIconByName(library.icon)), - selected: isSelected, // Makes the tile visually selected - onTap: () { - appLogger - .info('Selected library: ${library.name} (ID: ${library.id})'); - // Get current settings state - final currentSettings = ref.read(apiSettingsProvider); - // Update the active library ID - ref.read(apiSettingsProvider.notifier).updateState( - currentSettings.copyWith(activeLibraryId: library.id), - ); - // Close the dialog/bottom sheet - Navigator.pop(context); - }, - ); - }, - ); - } -} - class UserBar extends HookConsumerWidget { const UserBar({ super.key, @@ -367,3 +185,29 @@ class UserBar extends HookConsumerWidget { ); } } + +class VaaniLogo extends StatelessWidget { + const VaaniLogo({ + super.key, + this.size, + this.duration = const Duration(milliseconds: 750), + this.curve = Curves.fastOutSlowIn, + }); + + final double? size; + final Duration duration; + final Curve curve; + + @override + Widget build(BuildContext context) { + final IconThemeData iconTheme = IconTheme.of(context); + final double? iconSize = size ?? iconTheme.size; + return AnimatedContainer( + width: iconSize, + height: iconSize, + duration: duration, + curve: curve, + child: Image.asset('assets/images/vaani_logo_foreground.png'), + ); + } +} diff --git a/lib/shared/icons/abs_icons.dart b/lib/shared/icons/abs_icons.dart index eca3e1a..f112d0b 100644 --- a/lib/shared/icons/abs_icons.dart +++ b/lib/shared/icons/abs_icons.dart @@ -13,7 +13,6 @@ /// /// /// -library; // ignore_for_file: constant_identifier_names import 'package:flutter/widgets.dart' show IconData; diff --git a/lib/shared/widgets/vaani_logo.dart b/lib/shared/widgets/vaani_logo.dart deleted file mode 100644 index a5b4e11..0000000 --- a/lib/shared/widgets/vaani_logo.dart +++ /dev/null @@ -1,27 +0,0 @@ -import 'package:flutter/material.dart'; - -class VaaniLogo extends StatelessWidget { - const VaaniLogo({ - super.key, - this.size, - this.duration = const Duration(milliseconds: 750), - this.curve = Curves.fastOutSlowIn, - }); - - final double? size; - final Duration duration; - final Curve curve; - - @override - Widget build(BuildContext context) { - final IconThemeData iconTheme = IconTheme.of(context); - final double? iconSize = size ?? iconTheme.size; - return AnimatedContainer( - width: iconSize, - height: iconSize, - duration: duration, - curve: curve, - child: Image.asset('assets/images/vaani_logo_foreground.png'), - ); - } -} diff --git a/shelfsdk b/shelfsdk index e1848a4..5cc545c 160000 --- a/shelfsdk +++ b/shelfsdk @@ -1 +1 @@ -Subproject commit e1848a42c27257146015a33e9427f197f522fe03 +Subproject commit 5cc545ca87c05615473ab9c363cfa29e341d1e2a