替换miniPlayer

This commit is contained in:
rang 2025-11-13 17:53:23 +08:00
parent eb9b8f3b94
commit e67d045da6
34 changed files with 1777 additions and 1078 deletions

View file

@ -68,9 +68,9 @@ class AudiobookPlayerSeekChapterButton extends HookConsumerWidget {
return;
}
if (isForward) {
player.seekForward();
player.seekToNext();
} else {
player.seekBackward();
player.seekToPrevious();
}
},
);

View file

@ -5,7 +5,7 @@ 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'
import 'package:vaani/features/player/view/player_expanded.dart'
show pendingPlayerModals;
import 'package:vaani/features/player/view/widgets/playing_indicator_icon.dart';
import 'package:vaani/main.dart' show appLogger;
@ -117,7 +117,8 @@ class ChapterSelectionModal extends HookConsumerWidget {
key: isCurrent ? chapterKey : null,
onTap: () {
Navigator.of(context).pop();
notifier.seekInBook(chapter.start + 90.ms);
// notifier.seekInBook(chapter.start + 90.ms);
notifier.skipToChapter(chapter.id);
notifier.play();
},
);

View file

@ -0,0 +1,56 @@
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:just_audio/just_audio.dart';
import 'package:vaani/constants/sizes.dart';
import 'package:vaani/features/player/providers/audiobook_player.dart';
class AudiobookPlayerPlayPauseButton extends HookConsumerWidget {
const AudiobookPlayerPlayPauseButton({
super.key,
this.iconSize = 48.0,
});
final double iconSize;
@override
Widget build(BuildContext context, WidgetRef ref) {
final player = ref.watch(audiobookPlayerProvider);
final playing = ref.watch(isPlayerPlayingProvider);
final playPauseController = useAnimationController(
duration: const Duration(milliseconds: 200),
initialValue: 1,
);
if (playing) {
playPauseController.forward();
} else {
playPauseController.reverse();
}
return switch (player.processingState) {
ProcessingState.loading || ProcessingState.buffering => const Padding(
padding: EdgeInsets.all(AppElementSizes.paddingRegular),
child: CircularProgressIndicator(),
),
ProcessingState.completed => IconButton(
onPressed: () async {
await player.seekInBook(const Duration(seconds: 0));
await player.play();
},
icon: const Icon(
Icons.replay,
),
),
ProcessingState.ready => IconButton(
onPressed: () async {
await player.togglePlayPause();
},
iconSize: iconSize,
icon: AnimatedIcon(
icon: AnimatedIcons.play_pause,
progress: playPauseController,
),
),
ProcessingState.idle => const SizedBox.shrink(),
};
}
}

View file

@ -0,0 +1,82 @@
import 'package:audio_video_progress_bar/audio_video_progress_bar.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:vaani/features/player/providers/audiobook_player.dart';
import 'package:vaani/features/player/providers/currently_playing_provider.dart';
class AudiobookChapterProgressBar extends HookConsumerWidget {
const AudiobookChapterProgressBar({
super.key,
});
@override
Widget build(BuildContext context, WidgetRef ref) {
final player = ref.watch(audiobookPlayerProvider);
final currentChapter = ref.watch(currentPlayingChapterProvider);
final position = useStream(
player.positionStreamInBook,
initialData: const Duration(seconds: 0),
);
final buffered = useStream(
player.bufferedPositionStreamInBook,
initialData: const Duration(seconds: 0),
);
// 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 currentChapterBuffered = currentChapter == null
? null
: (player.bufferedPositionInBook - currentChapter.start);
return ProgressBar(
progress:
currentChapterProgress ?? position.data ?? const Duration(seconds: 0),
total: currentChapter == null
? player.book?.duration ?? const Duration(seconds: 0)
: currentChapter.end - currentChapter.start,
// ! TODO add onSeek
onSeek: (duration) {
player.seekInBook(
duration + (currentChapter?.start ?? const Duration(seconds: 0)),
);
// player.seek(duration);
},
thumbRadius: 8,
buffered:
currentChapterBuffered ?? buffered.data ?? const Duration(seconds: 0),
bufferedBarColor: Theme.of(context).colorScheme.secondary,
timeLabelType: TimeLabelType.remainingTime,
timeLabelLocation: TimeLabelLocation.below,
);
}
}
class AudiobookProgressBar extends HookConsumerWidget {
const AudiobookProgressBar({
super.key,
});
@override
Widget build(BuildContext context, WidgetRef ref) {
final player = ref.watch(audiobookPlayerProvider);
final position = useStream(
player.slowPositionStreamInBook,
initialData: const Duration(seconds: 0),
);
return ProgressBar(
progress: position.data ?? const Duration(seconds: 0),
total: player.book?.duration ?? const Duration(seconds: 0),
thumbRadius: 8,
bufferedBarColor: Theme.of(context).colorScheme.secondary,
timeLabelType: TimeLabelType.remainingTime,
timeLabelLocation: TimeLabelLocation.below,
);
}
}

View file

@ -3,7 +3,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:logging/logging.dart';
import 'package:vaani/features/per_book_settings/providers/book_settings_provider.dart';
import 'package:vaani/features/player/providers/audiobook_player.dart';
import 'package:vaani/features/player/view/player_when_expanded.dart';
import 'package:vaani/features/player/view/player_expanded.dart';
import 'package:vaani/features/player/view/widgets/speed_selector.dart';
import 'package:vaani/settings/app_settings_provider.dart';