Vaani/lib/features/player/view/player_minimized.dart

158 lines
5.4 KiB
Dart
Raw Normal View History

2025-11-13 17:53:23 +08:00
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
2025-11-22 15:54:29 +08:00
import 'package:flutter_platform_widgets/flutter_platform_widgets.dart';
2025-11-13 17:53:23 +08:00
import 'package:go_router/go_router.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:vaani/constants/sizes.dart';
2025-12-07 17:55:07 +08:00
import 'package:vaani/features/player/providers/abs_provider.dart';
import 'package:vaani/features/player/providers/audiobook_player.dart';
import 'package:vaani/features/player/providers/currently_playing_provider.dart';
2025-11-13 17:53:23 +08:00
import 'package:vaani/features/player/view/widgets/player_player_pause_button.dart';
import 'package:vaani/router/router.dart';
2025-12-07 17:55:07 +08:00
import 'package:vaani/shared/extensions/chapter.dart';
2025-12-01 15:34:12 +08:00
import 'package:vaani/shared/extensions/model_conversions.dart';
2025-11-13 17:53:23 +08:00
import 'package:vaani/shared/widgets/shelves/book_shelf.dart';
/// The height of the player when it is minimized
const double playerMinimizedHeight = 70;
class PlayerMinimized extends HookConsumerWidget {
const PlayerMinimized({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
2025-12-07 17:55:07 +08:00
final currentBook = ref.watch(absStateProvider.select((v) => v.book));
2025-12-01 15:34:12 +08:00
if (currentBook == null) {
2025-11-19 17:43:04 +08:00
return SizedBox.shrink();
2025-11-13 17:53:23 +08:00
}
2025-12-07 17:55:07 +08:00
final currentChapter =
ref.watch(absStateProvider.select((v) => v.currentChapter));
2025-11-13 17:53:23 +08:00
return PlayerMinimizedFramework(
children: [
// image
Padding(
padding: EdgeInsets.all(AppElementSizes.paddingSmall),
child: GestureDetector(
2025-11-13 17:53:23 +08:00
onTap: () {
// navigate to item page
context.pushNamed(
Routes.libraryItem.name,
pathParameters: {
2025-12-01 15:34:12 +08:00
Routes.libraryItem.pathParamName!: currentBook.libraryItemId,
2025-11-13 17:53:23 +08:00
},
);
},
child: ConstrainedBox(
constraints: BoxConstraints(
maxWidth: playerMinimizedHeight,
),
2025-11-19 17:43:04 +08:00
child: BookCoverWidget(),
2025-11-13 17:53:23 +08:00
),
),
),
// author and title of the book
Expanded(
child: Padding(
padding: const EdgeInsets.only(
left: AppElementSizes.paddingRegular,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: [
// AutoScrollText(
2025-11-22 15:54:29 +08:00
PlatformText(
2025-12-01 15:34:12 +08:00
'${currentBook.metadata.title ?? ''} - ${currentChapter?.title ?? ''}',
2025-11-13 17:53:23 +08:00
maxLines: 1, overflow: TextOverflow.ellipsis,
// velocity:
// const Velocity(pixelsPerSecond: Offset(16, 0)),
style: Theme.of(context).textTheme.bodyLarge,
),
2025-11-22 15:54:29 +08:00
PlatformText(
2025-12-01 15:34:12 +08:00
currentBook.metadata.asBookMetadataExpanded.authorName ?? '',
2025-11-13 17:53:23 +08:00
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
color: Theme.of(context)
.colorScheme
.onSurface
.withValues(alpha: 0.7),
),
),
],
),
),
),
// rewind button
Padding(
padding: const EdgeInsets.only(left: 8),
2025-11-22 15:54:29 +08:00
child: PlatformIconButton(
2025-11-13 17:53:23 +08:00
icon: const Icon(
Icons.replay_30,
size: AppElementSizes.iconSizeSmall,
),
onPressed: () {},
),
),
// play/pause button
Padding(
padding: const EdgeInsets.only(right: 8),
child: AudiobookPlayerPlayPauseButton(),
),
],
);
}
}
class PlayerMinimizedFramework extends HookConsumerWidget {
final List<Widget> children;
const PlayerMinimizedFramework({super.key, required this.children});
@override
Widget build(BuildContext context, WidgetRef ref) {
2025-12-07 17:55:07 +08:00
// final player = ref.watch(playerProvider);
final currentChapter =
ref.watch(absStateProvider.select((v) => v.currentChapter));
2025-11-13 17:53:23 +08:00
final progress =
2025-12-07 17:55:07 +08:00
// useStream(player.positionStreamInChapter, initialData: Duration.zero);
useStream(ref.read(absStateProvider.notifier).positionStreamInChapter,
initialData: Duration.zero);
2025-11-13 17:53:23 +08:00
return GestureDetector(
onTap: () {
if (GoRouterState.of(context).topRoute?.name != Routes.player.name) {
context.pushNamed(Routes.player.name);
} else {
context.pop();
}
},
2025-11-13 17:53:23 +08:00
child: Container(
height: playerMinimizedHeight,
color: Theme.of(context).colorScheme.surface,
child: Stack(
alignment: Alignment.topCenter,
children: [
Row(
children: children,
),
SizedBox(
height: AppElementSizes.barHeight,
child: LinearProgressIndicator(
value: (progress.data ?? Duration.zero).inSeconds /
2025-12-07 17:55:07 +08:00
(currentChapter?.duration.inSeconds ?? 1),
2025-11-22 15:54:29 +08:00
// color: Theme.of(context).colorScheme.onPrimaryContainer,
// backgroundColor: Theme.of(context).colorScheme.primaryContainer,
2025-11-13 17:53:23 +08:00
),
),
],
),
),
);
}
}