mirror of
https://github.com/Dr-Blank/Vaani.git
synced 2026-02-16 14:29:35 +00:00
格式化代码
This commit is contained in:
parent
a28547685b
commit
b3a9d76c78
24 changed files with 611 additions and 451 deletions
|
|
@ -26,8 +26,8 @@ class ExplorePage extends HookConsumerWidget {
|
|||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
// hooks for the dark mode
|
||||
final settings = ref.watch(appSettingsProvider);
|
||||
final api = ref.watch(authenticatedApiProvider);
|
||||
ref.watch(appSettingsProvider);
|
||||
// final api = ref.watch(authenticatedApiProvider);
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(S.of(context).explore),
|
||||
|
|
@ -62,8 +62,8 @@ class MySearchBar extends HookConsumerWidget {
|
|||
currentQuery = query;
|
||||
|
||||
// In a real application, there should be some error handling here.
|
||||
final options =
|
||||
await api.libraries.search(libraryId: settings.activeLibraryId!, query: query, limit: 3);
|
||||
final options = await api.libraries
|
||||
.search(libraryId: settings.activeLibraryId!, query: query, limit: 3);
|
||||
|
||||
// If another search happened after this one, throw away these options.
|
||||
if (currentQuery != query) {
|
||||
|
|
@ -98,7 +98,10 @@ class MySearchBar extends HookConsumerWidget {
|
|||
// opacity: 0.5 for the hint text
|
||||
hintStyle: WidgetStatePropertyAll(
|
||||
Theme.of(context).textTheme.bodyMedium!.copyWith(
|
||||
color: Theme.of(context).colorScheme.onSurface.withValues(alpha: 0.5),
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.onSurface
|
||||
.withValues(alpha: 0.5),
|
||||
),
|
||||
),
|
||||
textInputAction: TextInputAction.search,
|
||||
|
|
@ -231,8 +234,9 @@ class BookSearchResultMini extends HookConsumerWidget {
|
|||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final item = ref.watch(libraryItemProvider(book.libraryItemId)).valueOrNull;
|
||||
final image =
|
||||
item == null ? const AsyncValue.loading() : ref.watch(coverImageProvider(item.id));
|
||||
final image = item == null
|
||||
? const AsyncValue.loading()
|
||||
: ref.watch(coverImageProvider(item.id));
|
||||
return ListTile(
|
||||
leading: SizedBox(
|
||||
width: 50,
|
||||
|
|
|
|||
|
|
@ -77,9 +77,11 @@ class LibraryItemActions extends HookConsumerWidget {
|
|||
IconButton(
|
||||
onPressed: () {
|
||||
appLogger.fine('Sharing');
|
||||
var currentServerUrl = apiSettings.activeServer!.serverUrl;
|
||||
var currentServerUrl =
|
||||
apiSettings.activeServer!.serverUrl;
|
||||
if (!currentServerUrl.hasScheme) {
|
||||
currentServerUrl = Uri.https(currentServerUrl.toString());
|
||||
currentServerUrl =
|
||||
Uri.https(currentServerUrl.toString());
|
||||
}
|
||||
handleLaunchUrl(
|
||||
Uri.parse(
|
||||
|
|
@ -138,7 +140,8 @@ class LibraryItemActions extends HookConsumerWidget {
|
|||
FileDownloader()
|
||||
.database
|
||||
.deleteRecordWithId(
|
||||
record.task.taskId,
|
||||
record
|
||||
.task.taskId,
|
||||
);
|
||||
Navigator.pop(context);
|
||||
},
|
||||
|
|
@ -157,7 +160,8 @@ class LibraryItemActions extends HookConsumerWidget {
|
|||
},
|
||||
onTap: () async {
|
||||
// open the file location
|
||||
final didOpen = await FileDownloader().openFile(
|
||||
final didOpen =
|
||||
await FileDownloader().openFile(
|
||||
task: record.task,
|
||||
);
|
||||
|
||||
|
|
@ -226,7 +230,9 @@ class LibItemDownloadButton extends HookConsumerWidget {
|
|||
onPressed: () {
|
||||
appLogger.fine('Pressed download button');
|
||||
|
||||
ref.read(downloadManagerProvider.notifier).queueAudioBookDownload(item);
|
||||
ref
|
||||
.read(downloadManagerProvider.notifier)
|
||||
.queueAudioBookDownload(item);
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons.download_rounded,
|
||||
|
|
@ -245,7 +251,10 @@ class ItemCurrentlyInDownloadQueue extends HookConsumerWidget {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final progress = ref.watch(itemDownloadProgressProvider(item.id)).valueOrNull?.clamp(0.05, 1.0);
|
||||
final progress = ref
|
||||
.watch(itemDownloadProgressProvider(item.id))
|
||||
.valueOrNull
|
||||
?.clamp(0.05, 1.0);
|
||||
|
||||
if (progress == 1) {
|
||||
return AlreadyItemDownloadedButton(item: item);
|
||||
|
|
@ -333,7 +342,7 @@ class DownloadSheet extends HookConsumerWidget {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final manager = ref.watch(downloadManagerProvider);
|
||||
// final manager = ref.watch(downloadManagerProvider);
|
||||
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
|
|
@ -377,7 +386,9 @@ class DownloadSheet extends HookConsumerWidget {
|
|||
TextButton(
|
||||
onPressed: () {
|
||||
// delete the file
|
||||
ref.read(downloadManagerProvider.notifier).deleteDownloadedItem(
|
||||
ref
|
||||
.read(downloadManagerProvider.notifier)
|
||||
.deleteDownloadedItem(
|
||||
item,
|
||||
);
|
||||
GoRouter.of(context).pop(true);
|
||||
|
|
@ -396,7 +407,8 @@ class DownloadSheet extends HookConsumerWidget {
|
|||
);
|
||||
|
||||
if (wasDeleted ?? false) {
|
||||
appLogger.fine(S.of(context).deleted(item.media.metadata.title ?? ''));
|
||||
appLogger
|
||||
.fine(S.of(context).deleted(item.media.metadata.title ?? ''));
|
||||
GoRouter.of(context).pop();
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
|
|
@ -520,7 +532,8 @@ Future<void> libraryItemPlayButtonOnPressed({
|
|||
appLogger.info('Setting the book ${book.libraryItemId}');
|
||||
appLogger.info('Initial position: ${userMediaProgress?.currentTime}');
|
||||
final downloadManager = ref.watch(simpleDownloadManagerProvider);
|
||||
final libItem = await ref.read(libraryItemProvider(book.libraryItemId).future);
|
||||
final libItem =
|
||||
await ref.read(libraryItemProvider(book.libraryItemId).future);
|
||||
final downloadedUris = await downloadManager.getDownloadedFilesUri(libItem);
|
||||
setSourceFuture = player.setSourceAudiobook(
|
||||
book,
|
||||
|
|
@ -536,23 +549,27 @@ Future<void> libraryItemPlayButtonOnPressed({
|
|||
}
|
||||
}
|
||||
// set the volume as this is the first time playing and dismissing causes the volume to go to 0
|
||||
var bookPlayerSettings = ref.read(bookSettingsProvider(book.libraryItemId)).playerSettings;
|
||||
var bookPlayerSettings =
|
||||
ref.read(bookSettingsProvider(book.libraryItemId)).playerSettings;
|
||||
var appPlayerSettings = ref.read(appSettingsProvider).playerSettings;
|
||||
|
||||
var configurePlayerForEveryBook = appPlayerSettings.configurePlayerForEveryBook;
|
||||
var configurePlayerForEveryBook =
|
||||
appPlayerSettings.configurePlayerForEveryBook;
|
||||
|
||||
await Future.wait([
|
||||
setSourceFuture ?? Future.value(),
|
||||
// set the volume
|
||||
player.setVolume(
|
||||
configurePlayerForEveryBook
|
||||
? bookPlayerSettings.preferredDefaultVolume ?? appPlayerSettings.preferredDefaultVolume
|
||||
? bookPlayerSettings.preferredDefaultVolume ??
|
||||
appPlayerSettings.preferredDefaultVolume
|
||||
: appPlayerSettings.preferredDefaultVolume,
|
||||
),
|
||||
// set the speed
|
||||
player.setSpeed(
|
||||
configurePlayerForEveryBook
|
||||
? bookPlayerSettings.preferredDefaultSpeed ?? appPlayerSettings.preferredDefaultSpeed
|
||||
? bookPlayerSettings.preferredDefaultSpeed ??
|
||||
appPlayerSettings.preferredDefaultSpeed
|
||||
: appPlayerSettings.preferredDefaultSpeed,
|
||||
),
|
||||
]);
|
||||
|
|
|
|||
|
|
@ -25,8 +25,9 @@ class LibraryItemMetadata extends HookConsumerWidget {
|
|||
if (book == null) {
|
||||
return null;
|
||||
}
|
||||
final duration =
|
||||
book.audioFiles.map((e) => e.duration).reduce((value, element) => value + element);
|
||||
final duration = book.audioFiles
|
||||
.map((e) => e.duration)
|
||||
.reduce((value, element) => value + element);
|
||||
final hours = duration.inHours;
|
||||
final minutes = duration.inMinutes.remainder(60);
|
||||
return '${hours}h ${minutes}m';
|
||||
|
|
@ -41,8 +42,9 @@ class LibraryItemMetadata extends HookConsumerWidget {
|
|||
if (book == null) {
|
||||
return null;
|
||||
}
|
||||
final size =
|
||||
book.audioFiles.map((e) => e.metadata.size).reduce((value, element) => value + element);
|
||||
final size = book.audioFiles
|
||||
.map((e) => e.metadata.size)
|
||||
.reduce((value, element) => value + element);
|
||||
if (size / 1024 / 1024 < 1024) {
|
||||
return '${(size / 1024 / 1024).toStringAsFixed(2)} MB';
|
||||
}
|
||||
|
|
@ -98,7 +100,10 @@ class LibraryItemMetadata extends HookConsumerWidget {
|
|||
return VerticalDivider(
|
||||
indent: 6,
|
||||
endIndent: 6,
|
||||
color: Theme.of(context).colorScheme.onSurface.withValues(alpha: 0.6),
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.onSurface
|
||||
.withValues(alpha: 0.6),
|
||||
);
|
||||
},
|
||||
),
|
||||
|
|
|
|||
|
|
@ -28,7 +28,8 @@ class LibraryItemPage extends HookConsumerWidget {
|
|||
static const double _showFabThreshold = 300.0;
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final additionalItemData = extra is LibraryItemExtras ? extra as LibraryItemExtras : null;
|
||||
final additionalItemData =
|
||||
extra is LibraryItemExtras ? extra as LibraryItemExtras : null;
|
||||
final scrollController = useScrollController();
|
||||
final showFab = useState(false);
|
||||
|
||||
|
|
@ -151,7 +152,8 @@ class LibraryItemDescription extends HookConsumerWidget {
|
|||
}
|
||||
return ExpandableDescription(
|
||||
title: S.of(context).bookAbout,
|
||||
content: item.media.metadata.description ?? S.of(context).bookAboutDefault,
|
||||
content:
|
||||
item.media.metadata.description ?? S.of(context).bookAboutDefault,
|
||||
readMoreText: S.of(context).readMore,
|
||||
readLessText: S.of(context).readLess,
|
||||
);
|
||||
|
|
@ -168,8 +170,10 @@ double calculateWidth(
|
|||
/// height ratio of the cover image to the available height
|
||||
double maxHeightToUse = 0.25,
|
||||
}) {
|
||||
final availHeight = min(constraints.maxHeight, MediaQuery.of(context).size.height);
|
||||
final availWidth = min(constraints.maxWidth, MediaQuery.of(context).size.width);
|
||||
final availHeight =
|
||||
min(constraints.maxHeight, MediaQuery.of(context).size.height);
|
||||
final availWidth =
|
||||
min(constraints.maxWidth, MediaQuery.of(context).size.width);
|
||||
|
||||
// make the width widthRatio of the available width
|
||||
var width = availWidth * widthRatio;
|
||||
|
|
|
|||
|
|
@ -2,11 +2,13 @@ import 'package:flutter/material.dart';
|
|||
import 'package:go_router/go_router.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:vaani/api/library_provider.dart' show currentLibraryProvider;
|
||||
import 'package:vaani/features/you/view/widgets/library_switch_chip.dart' show showLibrarySwitcher;
|
||||
import 'package:vaani/features/you/view/widgets/library_switch_chip.dart'
|
||||
show showLibrarySwitcher;
|
||||
import 'package:vaani/generated/l10n.dart';
|
||||
import 'package:vaani/router/router.dart' show Routes;
|
||||
import 'package:vaani/shared/icons/abs_icons.dart' show AbsIcons;
|
||||
import 'package:vaani/shared/widgets/not_implemented.dart' show showNotImplementedToast;
|
||||
import 'package:vaani/shared/widgets/not_implemented.dart'
|
||||
show showNotImplementedToast;
|
||||
|
||||
class LibraryBrowserPage extends HookConsumerWidget {
|
||||
const LibraryBrowserPage({super.key});
|
||||
|
|
@ -32,7 +34,9 @@ class LibraryBrowserPage extends HookConsumerWidget {
|
|||
// true, // Optional: uncomment if you want snapping behavior (usually with floating: true)
|
||||
leading: IconButton(
|
||||
icon: Icon(libraryIconData),
|
||||
tooltip: S.of(context).librarySwitchTooltip, // Helpful tooltip for users
|
||||
tooltip: S
|
||||
.of(context)
|
||||
.librarySwitchTooltip, // Helpful tooltip for users
|
||||
onPressed: () {
|
||||
showLibrarySwitcher(context, ref);
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
import 'package:logging/logging.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
import 'package:vaani/db/available_boxes.dart';
|
||||
import 'package:vaani/features/per_book_settings/models/book_settings.dart' as model;
|
||||
import 'package:vaani/features/per_book_settings/models/book_settings.dart'
|
||||
as model;
|
||||
import 'package:vaani/features/per_book_settings/models/nullable_player_settings.dart';
|
||||
|
||||
part 'book_settings_provider.g.dart';
|
||||
|
|
|
|||
|
|
@ -122,9 +122,11 @@ class AudiobookPlayer extends AudioPlayer {
|
|||
final trackToPlay = getTrackToPlay(book, initialPosition ?? Duration.zero);
|
||||
|
||||
final initialIndex = book.tracks.indexOf(trackToPlay);
|
||||
final initialPositionInTrack =
|
||||
initialPosition != null ? initialPosition - trackToPlay.startOffset : null;
|
||||
await setAudioSourceTrack(initialIndex, initialPosition: initialPositionInTrack);
|
||||
final initialPositionInTrack = initialPosition != null
|
||||
? initialPosition - trackToPlay.startOffset
|
||||
: null;
|
||||
await setAudioSourceTrack(initialIndex,
|
||||
initialPosition: initialPositionInTrack);
|
||||
// _logger.finer('Setting audioSource');
|
||||
// await setAudioSource(
|
||||
// preload: preload,
|
||||
|
|
@ -158,7 +160,8 @@ class AudiobookPlayer extends AudioPlayer {
|
|||
// });
|
||||
}
|
||||
|
||||
Future<void> setAudioSourceTrack(int index, {Duration? initialPosition}) async {
|
||||
Future<void> setAudioSourceTrack(int index,
|
||||
{Duration? initialPosition}) async {
|
||||
if (_book == null) {
|
||||
return stop();
|
||||
}
|
||||
|
|
@ -168,9 +171,11 @@ class AudiobookPlayer extends AudioPlayer {
|
|||
_currentIndex = index;
|
||||
AudioTrack track = _book!.tracks[index];
|
||||
final appSettings = loadOrCreateAppSettings();
|
||||
final playerSettings = readFromBoxOrCreate(_book!.libraryItemId).playerSettings;
|
||||
final playerSettings =
|
||||
readFromBoxOrCreate(_book!.libraryItemId).playerSettings;
|
||||
|
||||
final retrievedUri = _getUri(track, _downloadedUris, baseUrl: baseUrl, token: token);
|
||||
final retrievedUri =
|
||||
_getUri(track, _downloadedUris, baseUrl: baseUrl, token: token);
|
||||
|
||||
await setAudioSource(
|
||||
initialPosition: initialPosition == null || initialPosition <= Duration()
|
||||
|
|
@ -185,8 +190,10 @@ class AudiobookPlayer extends AudioPlayer {
|
|||
// Specify a unique ID for each media item:
|
||||
id: '${book?.libraryItemId}${track.index}',
|
||||
// Metadata to display in the notification:
|
||||
title: appSettings.notificationSettings.primaryTitle.formatNotificationTitle(book!),
|
||||
album: appSettings.notificationSettings.secondaryTitle.formatNotificationTitle(book!),
|
||||
title: appSettings.notificationSettings.primaryTitle
|
||||
.formatNotificationTitle(book!),
|
||||
album: appSettings.notificationSettings.secondaryTitle
|
||||
.formatNotificationTitle(book!),
|
||||
artUri: Uri.parse(
|
||||
'$baseUrl/api/items/${book?.libraryItemId}/cover?token=$token&width=800',
|
||||
),
|
||||
|
|
@ -392,7 +399,8 @@ Uri _getUri(
|
|||
},
|
||||
);
|
||||
|
||||
return uri ?? Uri.parse('${baseUrl.toString()}${track.contentUrl}?token=$token');
|
||||
return uri ??
|
||||
Uri.parse('${baseUrl.toString()}${track.contentUrl}?token=$token');
|
||||
}
|
||||
|
||||
extension FormatNotificationTitle on String {
|
||||
|
|
|
|||
|
|
@ -31,7 +31,8 @@ class AudiobookPlayer extends HookConsumerWidget {
|
|||
if (currentBook == null) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
final itemBeingPlayed = ref.watch(libraryItemProvider(currentBook.libraryItemId));
|
||||
final itemBeingPlayed =
|
||||
ref.watch(libraryItemProvider(currentBook.libraryItemId));
|
||||
final player = ref.watch(audiobookPlayerProvider);
|
||||
final imageOfItemBeingPlayed = itemBeingPlayed.valueOrNull != null
|
||||
? ref.watch(
|
||||
|
|
@ -64,7 +65,8 @@ class AudiobookPlayer extends HookConsumerWidget {
|
|||
themeOfLibraryItemProvider(
|
||||
itemBeingPlayed.valueOrNull?.id,
|
||||
brightness: Theme.of(context).brightness,
|
||||
highContrast: appSettings.themeSettings.highContrast || MediaQuery.of(context).highContrast,
|
||||
highContrast: appSettings.themeSettings.highContrast ||
|
||||
MediaQuery.of(context).highContrast,
|
||||
),
|
||||
);
|
||||
|
||||
|
|
@ -86,7 +88,8 @@ class AudiobookPlayer extends HookConsumerWidget {
|
|||
onDragDown: (percentage) async {
|
||||
// preferred volume
|
||||
// set volume to 0 when dragging down
|
||||
await player.setVolume(preferredVolume * (1 - percentage.clamp(0, .75)));
|
||||
await player
|
||||
.setVolume(preferredVolume * (1 - percentage.clamp(0, .75)));
|
||||
},
|
||||
minHeight: playerMinHeight,
|
||||
// subtract the height of notches and other system UI
|
||||
|
|
@ -106,8 +109,10 @@ class AudiobookPlayer extends HookConsumerWidget {
|
|||
// at what point should the player switch from miniplayer to expanded player
|
||||
// also at this point the image should be at its max size and in the center of the player
|
||||
final miniplayerPercentageDeclaration =
|
||||
(maxImgSize - playerMinHeight) / (playerMaxHeight - playerMinHeight);
|
||||
final bool isFormMiniplayer = percentage < miniplayerPercentageDeclaration;
|
||||
(maxImgSize - playerMinHeight) /
|
||||
(playerMaxHeight - playerMinHeight);
|
||||
final bool isFormMiniplayer =
|
||||
percentage < miniplayerPercentageDeclaration;
|
||||
|
||||
if (!isFormMiniplayer) {
|
||||
// this calculation needs a refactor
|
||||
|
|
@ -207,14 +212,17 @@ class AudiobookChapterProgressBar extends HookConsumerWidget {
|
|||
|
||||
// now find the chapter that corresponds to the current time
|
||||
// and calculate the progress of the current chapter
|
||||
final currentChapterProgress =
|
||||
currentChapter == null ? null : (player.positionInBook - currentChapter.start);
|
||||
final currentChapterProgress = currentChapter == null
|
||||
? null
|
||||
: (player.positionInBook - currentChapter.start);
|
||||
|
||||
final currentChapterBuffered =
|
||||
currentChapter == null ? null : (player.bufferedPositionInBook - currentChapter.start);
|
||||
final currentChapterBuffered = currentChapter == null
|
||||
? null
|
||||
: (player.bufferedPositionInBook - currentChapter.start);
|
||||
|
||||
return ProgressBar(
|
||||
progress: currentChapterProgress ?? position.data ?? const Duration(seconds: 0),
|
||||
progress:
|
||||
currentChapterProgress ?? position.data ?? const Duration(seconds: 0),
|
||||
total: currentChapter == null
|
||||
? player.book?.duration ?? const Duration(seconds: 0)
|
||||
: currentChapter.end - currentChapter.start,
|
||||
|
|
@ -226,7 +234,8 @@ class AudiobookChapterProgressBar extends HookConsumerWidget {
|
|||
player.seek(duration);
|
||||
},
|
||||
thumbRadius: 8,
|
||||
buffered: currentChapterBuffered ?? buffered.data ?? const Duration(seconds: 0),
|
||||
buffered:
|
||||
currentChapterBuffered ?? buffered.data ?? const Duration(seconds: 0),
|
||||
bufferedBarColor: Theme.of(context).colorScheme.secondary,
|
||||
timeLabelType: TimeLabelType.remainingTime,
|
||||
timeLabelLocation: TimeLabelLocation.below,
|
||||
|
|
|
|||
|
|
@ -105,7 +105,10 @@ class PlayerWhenExpanded extends HookConsumerWidget {
|
|||
decoration: BoxDecoration(
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Theme.of(context).colorScheme.primary.withValues(alpha: 0.1),
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.primary
|
||||
.withValues(alpha: 0.1),
|
||||
blurRadius: 32 * earlyPercentage,
|
||||
spreadRadius: 8 * earlyPercentage,
|
||||
// offset: Offset(0, 16 * earlyPercentage),
|
||||
|
|
@ -171,7 +174,10 @@ class PlayerWhenExpanded extends HookConsumerWidget {
|
|||
currentBookMetadata?.authorName ?? '',
|
||||
].join(' - '),
|
||||
style: Theme.of(context).textTheme.titleMedium?.copyWith(
|
||||
color: Theme.of(context).colorScheme.onSurface.withValues(alpha: 0.7),
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.onSurface
|
||||
.withValues(alpha: 0.7),
|
||||
),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
|
|
|
|||
|
|
@ -34,7 +34,8 @@ class PlayerWhenMinimized extends HookConsumerWidget {
|
|||
final currentChapter = ref.watch(currentPlayingChapterProvider);
|
||||
|
||||
final vanishingPercentage = 1 - percentageMiniplayer;
|
||||
final progress = useStream(player.slowPositionStreamInBook, initialData: Duration.zero);
|
||||
final progress =
|
||||
useStream(player.slowPositionStreamInBook, initialData: Duration.zero);
|
||||
|
||||
final bookMetaExpanded = ref.watch(currentBookMetadataProvider);
|
||||
|
||||
|
|
@ -56,7 +57,8 @@ class PlayerWhenMinimized extends HookConsumerWidget {
|
|||
context.pushNamed(
|
||||
Routes.libraryItem.name,
|
||||
pathParameters: {
|
||||
Routes.libraryItem.pathParamName!: player.book!.libraryItemId,
|
||||
Routes.libraryItem.pathParamName!:
|
||||
player.book!.libraryItemId,
|
||||
},
|
||||
);
|
||||
},
|
||||
|
|
@ -90,7 +92,10 @@ class PlayerWhenMinimized extends HookConsumerWidget {
|
|||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
|
||||
color: Theme.of(context).colorScheme.onSurface.withValues(alpha: 0.7),
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.onSurface
|
||||
.withValues(alpha: 0.7),
|
||||
),
|
||||
),
|
||||
],
|
||||
|
|
@ -134,7 +139,8 @@ class PlayerWhenMinimized extends HookConsumerWidget {
|
|||
SizedBox(
|
||||
height: barHeight,
|
||||
child: LinearProgressIndicator(
|
||||
value: (progress.data ?? Duration.zero).inSeconds / player.book!.duration.inSeconds,
|
||||
value: (progress.data ?? Duration.zero).inSeconds /
|
||||
player.book!.duration.inSeconds,
|
||||
color: Theme.of(context).colorScheme.onPrimaryContainer,
|
||||
backgroundColor: Theme.of(context).colorScheme.primaryContainer,
|
||||
),
|
||||
|
|
|
|||
|
|
@ -1,14 +1,17 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_animate/flutter_animate.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:vaani/features/player/providers/audiobook_player.dart' show audiobookPlayerProvider;
|
||||
import 'package:vaani/features/player/providers/audiobook_player.dart'
|
||||
show audiobookPlayerProvider;
|
||||
import 'package:vaani/features/player/providers/currently_playing_provider.dart'
|
||||
show currentPlayingChapterProvider, currentlyPlayingBookProvider;
|
||||
import 'package:vaani/features/player/view/player_when_expanded.dart' show pendingPlayerModals;
|
||||
import 'package:vaani/features/player/view/player_when_expanded.dart'
|
||||
show pendingPlayerModals;
|
||||
import 'package:vaani/features/player/view/widgets/playing_indicator_icon.dart';
|
||||
import 'package:vaani/main.dart' show appLogger;
|
||||
import 'package:vaani/shared/extensions/chapter.dart' show ChapterDuration;
|
||||
import 'package:vaani/shared/extensions/duration_format.dart' show DurationFormat;
|
||||
import 'package:vaani/shared/extensions/duration_format.dart'
|
||||
show DurationFormat;
|
||||
import 'package:vaani/shared/hooks.dart' show useTimer;
|
||||
|
||||
class ChapterSelectionButton extends HookConsumerWidget {
|
||||
|
|
@ -88,11 +91,13 @@ class ChapterSelectionModal extends HookConsumerWidget {
|
|||
children: currentBook!.chapters.map(
|
||||
(chapter) {
|
||||
final isCurrent = currentChapterIndex == chapter.id;
|
||||
final isPlayed =
|
||||
currentChapterIndex != null && chapter.id < currentChapterIndex;
|
||||
final isPlayed = currentChapterIndex != null &&
|
||||
chapter.id < currentChapterIndex;
|
||||
return ListTile(
|
||||
autofocus: isCurrent,
|
||||
iconColor: isPlayed && !isCurrent ? theme.disabledColor : null,
|
||||
iconColor: isPlayed && !isCurrent
|
||||
? theme.disabledColor
|
||||
: null,
|
||||
title: Text(
|
||||
chapter.title,
|
||||
style: isPlayed && !isCurrent
|
||||
|
|
|
|||
|
|
@ -50,7 +50,8 @@ class PlayerSkipChapterStartEnd extends HookConsumerWidget {
|
|||
body: Column(
|
||||
children: [
|
||||
ListTile(
|
||||
title: Text('跳过片头 ${bookSettings.playerSettings.skipChapterStart.inSeconds}s'),
|
||||
title: Text(
|
||||
'跳过片头 ${bookSettings.playerSettings.skipChapterStart.inSeconds}s'),
|
||||
),
|
||||
Expanded(
|
||||
child: TimeIntervalSlider(
|
||||
|
|
@ -65,14 +66,16 @@ class PlayerSkipChapterStartEnd extends HookConsumerWidget {
|
|||
bookSettingsProvider(bookId).notifier,
|
||||
)
|
||||
.update(
|
||||
bookSettings.copyWith.playerSettings(skipChapterStart: interval),
|
||||
bookSettings.copyWith
|
||||
.playerSettings(skipChapterStart: interval),
|
||||
);
|
||||
ref.read(audiobookPlayerProvider).setClip(start: interval);
|
||||
},
|
||||
),
|
||||
),
|
||||
ListTile(
|
||||
title: Text('跳过片尾 ${bookSettings.playerSettings.skipChapterEnd.inSeconds}s'),
|
||||
title: Text(
|
||||
'跳过片尾 ${bookSettings.playerSettings.skipChapterEnd.inSeconds}s'),
|
||||
),
|
||||
Expanded(
|
||||
child: TimeIntervalSlider(
|
||||
|
|
@ -87,7 +90,8 @@ class PlayerSkipChapterStartEnd extends HookConsumerWidget {
|
|||
bookSettingsProvider(bookId).notifier,
|
||||
)
|
||||
.update(
|
||||
bookSettings.copyWith.playerSettings(skipChapterEnd: interval),
|
||||
bookSettings.copyWith
|
||||
.playerSettings(skipChapterEnd: interval),
|
||||
);
|
||||
},
|
||||
),
|
||||
|
|
|
|||
|
|
@ -3,7 +3,8 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
|
|||
import 'package:shelfsdk/audiobookshelf_api.dart' show Library;
|
||||
import 'package:vaani/api/library_provider.dart';
|
||||
import 'package:vaani/generated/l10n.dart';
|
||||
import 'package:vaani/settings/api_settings_provider.dart' show apiSettingsProvider;
|
||||
import 'package:vaani/settings/api_settings_provider.dart'
|
||||
show apiSettingsProvider;
|
||||
import 'package:vaani/shared/icons/abs_icons.dart';
|
||||
import 'dart:io' show Platform;
|
||||
|
||||
|
|
@ -99,7 +100,8 @@ void showLibrarySwitcher(
|
|||
// Make it scrollable and control height
|
||||
isScrollControlled: true,
|
||||
constraints: BoxConstraints(
|
||||
maxHeight: MediaQuery.of(context).size.height * 0.6, // Max 60% of screen
|
||||
maxHeight:
|
||||
MediaQuery.of(context).size.height * 0.6, // Max 60% of screen
|
||||
),
|
||||
builder: (sheetContext) => Padding(
|
||||
// Add padding within the bottom sheet
|
||||
|
|
|
|||
|
|
@ -68,7 +68,8 @@ class YouPage extends HookConsumerWidget {
|
|||
},
|
||||
),
|
||||
librariesAsyncValue.when(
|
||||
data: (libraries) => LibrarySwitchChip(libraries: libraries),
|
||||
data: (libraries) =>
|
||||
LibrarySwitchChip(libraries: libraries),
|
||||
loading: () => const ActionChip(
|
||||
avatar: SizedBox(
|
||||
width: 18,
|
||||
|
|
@ -88,7 +89,8 @@ class YouPage extends HookConsumerWidget {
|
|||
// Maybe show error details or allow retry
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text('Failed to load libraries: $error'),
|
||||
content:
|
||||
Text('Failed to load libraries: $error'),
|
||||
),
|
||||
);
|
||||
},
|
||||
|
|
@ -141,7 +143,8 @@ class YouPage extends HookConsumerWidget {
|
|||
icon: const Icon(Icons.info),
|
||||
applicationName: AppMetadata.appName,
|
||||
applicationVersion: AppMetadata.version,
|
||||
applicationLegalese: 'Made with ❤️ by ${AppMetadata.author}',
|
||||
applicationLegalese:
|
||||
'Made with ❤️ by ${AppMetadata.author}',
|
||||
aboutBoxChildren: [
|
||||
// link to github repo
|
||||
ListTile(
|
||||
|
|
@ -216,7 +219,8 @@ class UserBar extends HookConsumerWidget {
|
|||
Text(
|
||||
api.baseUrl.toString(),
|
||||
style: textTheme.bodyMedium?.copyWith(
|
||||
color: themeData.colorScheme.onSurface.withValues(alpha: 0.6),
|
||||
color:
|
||||
themeData.colorScheme.onSurface.withValues(alpha: 0.6),
|
||||
),
|
||||
),
|
||||
],
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue