feat: implement basic seekbar
This commit is contained in:
parent
2ef04267d7
commit
b1db0059eb
5 changed files with 156 additions and 45 deletions
|
@ -26,11 +26,19 @@ class AudioPlayerService {
|
|||
/// Registers listeners on the player
|
||||
void setup() {
|
||||
if (_setUp) return;
|
||||
_player.createPositionStream().listen((d) {
|
||||
if (!isPlaying) return;
|
||||
progressNotifier.value = [
|
||||
d.inSeconds,
|
||||
_songList[_player.currentIndex!].duration,
|
||||
];
|
||||
});
|
||||
_player.currentIndexStream.listen((index) {
|
||||
logger.d("Done fired");
|
||||
songNotifier.value = index == null ? null : _songList[index];
|
||||
_setColorScheme();
|
||||
});
|
||||
|
||||
_setUp = true;
|
||||
}
|
||||
|
||||
|
@ -70,10 +78,16 @@ class AudioPlayerService {
|
|||
logger.d("Playing ${_player.currentIndex}");
|
||||
}
|
||||
|
||||
/// Moves to the specified number of seconds
|
||||
Future<void> seek(double position) async {
|
||||
await _player.seek(Duration(seconds: position.toInt()));
|
||||
}
|
||||
|
||||
/// Sets color scheme from image
|
||||
Future<void> _setColorScheme() async {
|
||||
if (AudioPlayerService().song == null) {
|
||||
themeNotifier.value = ColorScheme.fromSeed(seedColor: Colors.deepPurple);
|
||||
return;
|
||||
}
|
||||
themeNotifier.value = await ColorScheme.fromImageProvider(
|
||||
provider: CachedNetworkImageProvider(
|
||||
|
|
|
@ -35,6 +35,9 @@ final ValueNotifier<ColorScheme> themeNotifier =
|
|||
/// Notifier to change theme from inside the app
|
||||
final ValueNotifier<Song?> songNotifier = ValueNotifier(null);
|
||||
|
||||
/// Notifier for the song progress bar
|
||||
final ValueNotifier<List<int>> progressNotifier = ValueNotifier([0, 1]);
|
||||
|
||||
/// Main app class
|
||||
class MyApp extends StatelessWidget {
|
||||
/// Main app class
|
||||
|
@ -58,8 +61,11 @@ class MyApp extends StatelessWidget {
|
|||
return Stack(
|
||||
children: [
|
||||
child!,
|
||||
Player(
|
||||
key: playerKey,
|
||||
Material(
|
||||
type: MaterialType.transparency,
|
||||
child: Player(
|
||||
key: playerKey,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import 'package:auto_size_text/auto_size_text.dart';
|
||||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_xlider/flutter_xlider.dart';
|
||||
import 'package:ocarina/api/audio/audioplayer_service.dart';
|
||||
import 'package:ocarina/api/subsonic/song.dart';
|
||||
import 'package:ocarina/main.dart';
|
||||
|
@ -208,57 +209,138 @@ class PlayerState extends State<Player> {
|
|||
),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
Container(
|
||||
// Full player controls here
|
||||
height: 90.h,
|
||||
color: Theme.of(context).colorScheme.primaryContainer,
|
||||
width: 100.w,
|
||||
child: Center(
|
||||
child: Column(
|
||||
children: [
|
||||
ClipRRect(
|
||||
child: (AudioPlayerService().song == null)
|
||||
? ColoredBox(
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.primaryContainer,
|
||||
child: Center(
|
||||
child: Icon(
|
||||
Icons.music_note,
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.onPrimaryContainer,
|
||||
),
|
||||
),
|
||||
)
|
||||
: (CachedNetworkImage(
|
||||
cacheKey: AudioPlayerService().song!.coverArtId,
|
||||
imageUrl:
|
||||
AudioPlayerService().song!.coverArtUrl,
|
||||
placeholder: (c, d) => Shimmer.fromColors(
|
||||
baseColor: Colors.grey.shade300,
|
||||
highlightColor: Colors.grey.shade100,
|
||||
child: Container(
|
||||
color: Colors.grey,
|
||||
),
|
||||
),
|
||||
errorWidget: (c, _, __) {
|
||||
logger
|
||||
..e(_)
|
||||
..e(__);
|
||||
return ColoredBox(
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.primaryContainer,
|
||||
child: Center(
|
||||
child: Icon(
|
||||
Icons.music_note,
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.onPrimaryContainer,
|
||||
),
|
||||
const SizedBox(
|
||||
height: 30,
|
||||
),
|
||||
SizedBox(
|
||||
width: 80.w,
|
||||
height: 80.w,
|
||||
child: ClipRRect(
|
||||
// borderRadius: BorderRadius.circular(16),
|
||||
child: (AudioPlayerService().song == null)
|
||||
? ColoredBox(
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.primaryContainer,
|
||||
child: Center(
|
||||
child: Icon(
|
||||
Icons.music_note,
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.onPrimaryContainer,
|
||||
),
|
||||
),
|
||||
)
|
||||
: (CachedNetworkImage(
|
||||
cacheKey:
|
||||
AudioPlayerService().song!.coverArtId,
|
||||
imageUrl:
|
||||
AudioPlayerService().song!.coverArtUrl,
|
||||
placeholder: (c, d) => Shimmer.fromColors(
|
||||
baseColor: Colors.grey.shade300,
|
||||
highlightColor: Colors.grey.shade100,
|
||||
child: Container(
|
||||
color: Colors.grey,
|
||||
),
|
||||
),
|
||||
errorWidget: (c, _, __) {
|
||||
logger
|
||||
..e(_)
|
||||
..e(__);
|
||||
return ColoredBox(
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.primaryContainer,
|
||||
child: Center(
|
||||
child: Icon(
|
||||
Icons.music_note,
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.onPrimaryContainer,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
)),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
SizedBox(
|
||||
width: 70.w,
|
||||
height: 40,
|
||||
child: AutoSizeText(
|
||||
AudioPlayerService().song?.title ?? "Nothing",
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 20.sp,
|
||||
),
|
||||
overflowReplacement: TextScroll(
|
||||
AudioPlayerService().song?.title ?? "Nothing",
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 20.sp,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
width: 70.w,
|
||||
height: 50,
|
||||
child: AutoSizeText(
|
||||
AudioPlayerService().song?.artistName ?? "Nobody",
|
||||
style: TextStyle(fontSize: 16.sp),
|
||||
textAlign: TextAlign.center,
|
||||
overflowReplacement: TextScroll(
|
||||
AudioPlayerService().song?.artistName ?? "Nobody",
|
||||
style: TextStyle(
|
||||
fontSize: 16.sp,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
SizedBox(
|
||||
width: 60.w,
|
||||
height: 40,
|
||||
child: Overlay(
|
||||
initialEntries: [
|
||||
OverlayEntry(
|
||||
builder: (c) => ValueListenableBuilder<List<int>>(
|
||||
valueListenable: progressNotifier,
|
||||
builder: (c, v, _) {
|
||||
return FlutterSlider(
|
||||
values: [v[0].toDouble()],
|
||||
max: v[1].toDouble(),
|
||||
min: 0,
|
||||
onDragCompleted:
|
||||
(handlerIndex, lowerValue, upperValue) {
|
||||
if (AudioPlayerService().song == null) {
|
||||
return;
|
||||
}
|
||||
logger.d(lowerValue);
|
||||
AudioPlayerService()
|
||||
.seek(lowerValue as double);
|
||||
},
|
||||
);
|
||||
},
|
||||
)),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
|
|
@ -368,6 +368,14 @@ packages:
|
|||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
flutter_xlider:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_xlider
|
||||
sha256: b83da229b8a2153adeefc5d9e08e0060689c8dc2187b30e3502cf67c1a6495be
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.5.0"
|
||||
frontend_server_client:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
|
@ -55,6 +55,7 @@ dependencies:
|
|||
shared_preferences: ^2.2.3
|
||||
dynamic_color: ^1.7.0
|
||||
cached_network_image: ^3.3.1
|
||||
flutter_xlider: ^3.5.0
|
||||
|
||||
dev_dependencies:
|
||||
build_runner: ^2.4.9
|
||||
|
|
Loading…
Reference in a new issue