Skip to content

Commit

Permalink
State handling of currently playing track and progress slider improved.
Browse files Browse the repository at this point in the history
  • Loading branch information
Kern, Thomas committed Jan 3, 2024
1 parent 5161f9a commit f456b1a
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 213 deletions.
71 changes: 21 additions & 50 deletions lib/pages/tracklist/now_playing.dart
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ class NowPlaying extends StatelessWidget {

final bool isStream;

const NowPlaying(this.splitPage, this.currentTlTrack, this.cover,
this.playbackState, this.timePosition, this.streamTitle, this.isStream,
const NowPlaying(this.splitPage, this.currentTlTrack, this.cover, this.playbackState, this.timePosition,
this.streamTitle, this.isStream,
{super.key});

@override
Expand All @@ -64,10 +64,7 @@ class NowPlaying extends StatelessWidget {
bitrate = currentTlTrack!.track.bitrate ?? 0;
} else {
title = currentTlTrack!.track.name;
artistName = currentTlTrack!.track.artists
.map((e) => e.name)
.nonNulls
.join(', ');
artistName = currentTlTrack!.track.artists.map((e) => e.name).nonNulls.join(', ');
albumName = currentTlTrack!.track.album?.name ?? '';
length = currentTlTrack!.track.length ?? 0;
date = currentTlTrack!.track.date ?? '';
Expand All @@ -78,61 +75,40 @@ class NowPlaying extends StatelessWidget {
}

if (splitPage) {
return _small(
title, artistName, albumName, length, timePosition, bitrate);
return _small(title, artistName, albumName, length, bitrate);
} else {
return _big(title, artistName, albumName, length, timePosition, date,
discNo, trackNo, bitrate);
return _big(title, artistName, albumName, length, date, discNo, trackNo, bitrate);
}
}

Widget _big(String title, String artistName, String albumName, length,
position, date, discNo, trackNo, int bitrate) {
Widget _big(String title, String artistName, String albumName, length, date, discNo, trackNo, int bitrate) {
return Expanded(
flex: 1,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Column(children: [
Container(
padding: const EdgeInsets.all(8),
child: Center(child: cover ?? const Icon(null))),
Center(
child: Text(title, style: const TextStyle(fontSize: 20.0))),
Center(
child:
Text(artistName, style: const TextStyle(fontSize: 18.0))),
Center(
child: Text(albumName,
style: const TextStyle(
fontSize: 14.0, fontStyle: FontStyle.italic)))
Container(padding: const EdgeInsets.all(8), child: Center(child: cover ?? const Icon(null))),
Center(child: Text(title, style: const TextStyle(fontSize: 20.0))),
Center(child: Text(artistName, style: const TextStyle(fontSize: 18.0))),
Center(child: Text(albumName, style: const TextStyle(fontSize: 14.0, fontStyle: FontStyle.italic)))
]),
Column(children: [
!isStream
? Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Text(S
.of(Globals.rootContext)
.nowPlayingDiscLbl(discNo)),
Text(S
.of(Globals.rootContext)
.nowPlayingTrackNoLbl(trackNo)),
Text(S
.of(Globals.rootContext)
.nowPlayingDateLbl(date)),
])
? Row(mainAxisSize: MainAxisSize.max, mainAxisAlignment: MainAxisAlignment.spaceAround, children: [
Text(S.of(Globals.rootContext).nowPlayingDiscLbl(discNo)),
Text(S.of(Globals.rootContext).nowPlayingTrackNoLbl(trackNo)),
Text(S.of(Globals.rootContext).nowPlayingDateLbl(date)),
])
: const SizedBox(),
PlayingProgressIndicator(Duration(milliseconds: length),
playbackState, position, bitrate, _getButtons, isStream)
PlayingProgressIndicator(
Duration(milliseconds: length), playbackState, timePosition, bitrate, _getButtons, isStream)
]),
],
));
}

Widget _small(String title, String artistName, String albumName, int length,
int position, int bitrate) {
Widget _small(String title, String artistName, String albumName, int length, int bitrate) {
return Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
Expand All @@ -144,8 +120,8 @@ class NowPlaying extends StatelessWidget {
subtitle: Text(artistName),
//trailing: Row(mainAxisSize: MainAxisSize.min, children: _getButtons()),
),
PlayingProgressIndicator(Duration(milliseconds: length), playbackState,
position, bitrate, _getButtons, isStream),
PlayingProgressIndicator(
Duration(milliseconds: length), playbackState, timePosition, bitrate, _getButtons, isStream),
],
);
}
Expand All @@ -154,12 +130,7 @@ class NowPlaying extends StatelessWidget {
if (playbackState == PlaybackState.playing) {
return [_PreviousButton(), _PauseButton(), _StopButton(), _NextButton()];
} else if (playbackState == PlaybackState.paused) {
return [
_PreviousButton(),
_PlayButton(null),
_StopButton(),
_NextButton()
];
return [_PreviousButton(), _PlayButton(null), _StopButton(), _NextButton()];
} else if (playbackState == PlaybackState.stopped) {
return [_PlayButton(currentTlTrack?.tlid)];
} else {
Expand Down
132 changes: 48 additions & 84 deletions lib/pages/tracklist/playing_progress.dart
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ import 'package:get_it/get_it.dart';
import 'package:mopicon/extensions/timestring.dart';
import 'package:mopicon/services/mopidy_service.dart';
import 'package:mopicon/utils/globals.dart';
import 'package:mopicon/generated/l10n.dart';

class PlayingProgressIndicator extends StatefulWidget {
final String playbackState;
Expand All @@ -34,48 +33,50 @@ class PlayingProgressIndicator extends StatefulWidget {
final List<Widget> Function()? buttons;
final bool isStream;

const PlayingProgressIndicator(this.duration, this.playbackState,
this.timePosition, this.bitrate, this.buttons, this.isStream,
const PlayingProgressIndicator(
this.duration, this.playbackState, this.timePosition, this.bitrate, this.buttons, this.isStream,
{super.key});

@override
State<PlayingProgressIndicator> createState() =>
_PlayingProgressIndicatorState();
State<PlayingProgressIndicator> createState() => _PlayingProgressIndicatorState();
}

class _PlayingProgressIndicatorState extends State<PlayingProgressIndicator>
with SingleTickerProviderStateMixin {
class _PlayingProgressIndicatorState extends State<PlayingProgressIndicator> with SingleTickerProviderStateMixin {
final mopidyService = GetIt.instance<MopidyService>();

late bool isStream;
late int timePosition;
late int bitrate;
late Duration duration;
late AnimationController controller;
String? previousPlaybackState;

@override
void initState() {
super.initState();
isStream = widget.isStream;
timePosition = widget.timePosition;
bitrate = widget.bitrate;
duration = widget.duration;
controller = AnimationController(
value: timePosition / duration.inMilliseconds,
setupAnimation();
}

double calculateValue() {
return duration.inMilliseconds > 0 ? timePosition / duration.inMilliseconds : 0;
}

/// [AnimationController]s can be created with `vsync: this` because of
/// [TickerProviderStateMixin].
setupAnimation() async {
controller = AnimationController(
vsync: this,
duration: duration,
)..addListener(() {
setState(() {
timePosition = (duration.inMilliseconds * controller.value).toInt();
});
});

if (widget.playbackState == PlaybackState.playing) {
controller.forward();
controller.forward(from: calculateValue());
}
super.initState();
}

@override
Expand All @@ -87,7 +88,7 @@ class _PlayingProgressIndicatorState extends State<PlayingProgressIndicator>
controller.stop(canceled: true);
controller.reset();
} else if (widget.playbackState == PlaybackState.playing) {
controller.forward();
controller.forward(from: calculateValue());
}
}
if (widget.duration != oldWidget.duration) {
Expand All @@ -96,7 +97,7 @@ class _PlayingProgressIndicatorState extends State<PlayingProgressIndicator>
duration = widget.duration;
timePosition = widget.timePosition;
if (widget.playbackState == PlaybackState.playing) {
controller.forward();
controller.forward(from: calculateValue());
}
}

Expand All @@ -111,7 +112,6 @@ class _PlayingProgressIndicatorState extends State<PlayingProgressIndicator>
isStream = widget.isStream;
});
}

super.didUpdateWidget(oldWidget);
}

Expand All @@ -126,76 +126,40 @@ class _PlayingProgressIndicatorState extends State<PlayingProgressIndicator>
String cp = timePosition.millisToTimeString();
String ep = duration.inMilliseconds.millisToTimeString();

var buttonChilds =
widget.buttons != null ? [...widget.buttons!()] : [const SizedBox()];
var buttonRow =
Row(mainAxisAlignment: MainAxisAlignment.end, children: buttonChilds);
var slider = Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisSize: MainAxisSize.max, children: [
Text(cp),
Expanded(
child: Slider(
value: calculateValue(),
onChanged: (double value) {
if (widget.playbackState != PlaybackState.stopped) {
controller.value = value;
}
},
onChangeEnd: (double value) async {
try {
var pos = (duration.inMilliseconds * value).toInt();
bool success = await mopidyService.seek(pos);
if (success) {
setState(() {
controller.value = value;
timePosition = pos;
});
}
} catch (e) {
Globals.logger.e(e);
}
},
)),
Text(ep),
]);

var buttonChilds = widget.buttons != null ? [...widget.buttons!()] : [const SizedBox()];
var buttonRow = Row(mainAxisAlignment: MainAxisAlignment.end, children: buttonChilds);
return Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
!isStream
? Slider(
value: controller.value,
divisions:
duration.inSeconds == 0 ? 5 : duration.inSeconds * 5,
//label: cp,
onChangeStart: (double value) async {
try {
previousPlaybackState =
await mopidyService.getPlaybackState();
if (previousPlaybackState != PlaybackState.stopped) {
await mopidyService.playback(
PlaybackAction.pause, null);
}
} catch (e) {
Globals.logger.e(e);
}
},
onChanged: widget.playbackState != PlaybackState.stopped
? (double value) {
if (previousPlaybackState != PlaybackState.stopped) {
controller.value = value;
}
}
: null,
onChangeEnd: (double value) async {
try {
if (previousPlaybackState != PlaybackState.stopped) {
var pos = (duration.inMilliseconds * value).toInt();
bool success = await mopidyService.seek(pos);
if (success) {
setState(() {
controller.value = value;
timePosition = pos;
});
}
if (previousPlaybackState == PlaybackState.playing) {
await mopidyService.playback(
PlaybackAction.resume, null);
}
}
} catch (e) {
Globals.logger.e(e);
}
},
)
: const SizedBox(),
Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
!isStream ? Text('$cp/$ep min') : const SizedBox(),
bitrate > 0
? Text(S
.of(context)
.nowPlayingBitrateLbl((bitrate / 1000).round()))
: const SizedBox(),
buttonRow
],
)
]);
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [!isStream ? slider : const SizedBox(), buttonRow]);
}
}
Loading

0 comments on commit f456b1a

Please sign in to comment.