mirror of
https://github.com/stonega/tsacdop
synced 2025-02-13 10:00:49 +01:00
Custom playlist support.
This commit is contained in:
parent
1d8db22dde
commit
963415ded4
@ -359,14 +359,15 @@ class __PlaylistButtonState extends State<_PlaylistButton> {
|
|||||||
topLeft: Radius.circular(10.0),
|
topLeft: Radius.circular(10.0),
|
||||||
topRight: Radius.circular(10.0)),
|
topRight: Radius.circular(10.0)),
|
||||||
),
|
),
|
||||||
child: Selector<AudioPlayerNotifier, Tuple3<bool, Playlist, int>>(
|
child: Selector<AudioPlayerNotifier,
|
||||||
selector: (_, audio) =>
|
Tuple3<bool, EpisodeBrief, int>>(
|
||||||
Tuple3(audio.playerRunning, audio.queue, audio.lastPositin),
|
selector: (_, audio) => Tuple3(
|
||||||
|
audio.playerRunning, audio.episode, audio.lastPositin),
|
||||||
builder: (_, data, __) => !_loadPlay
|
builder: (_, data, __) => !_loadPlay
|
||||||
? SizedBox(
|
? SizedBox(
|
||||||
height: 8.0,
|
height: 8.0,
|
||||||
)
|
)
|
||||||
: data.item1 || data.item2.episodes.isEmpty
|
: data.item1 || data.item2 == null
|
||||||
? SizedBox(
|
? SizedBox(
|
||||||
height: 8.0,
|
height: 8.0,
|
||||||
)
|
)
|
||||||
@ -390,8 +391,8 @@ class __PlaylistButtonState extends State<_PlaylistButton> {
|
|||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
CircleAvatar(
|
CircleAvatar(
|
||||||
radius: 20,
|
radius: 20,
|
||||||
backgroundImage: data
|
backgroundImage:
|
||||||
.item2.episodes.first.avatarImage),
|
data.item2.avatarImage),
|
||||||
Container(
|
Container(
|
||||||
height: 40.0,
|
height: 40.0,
|
||||||
width: 40.0,
|
width: 40.0,
|
||||||
@ -419,7 +420,7 @@ class __PlaylistButtonState extends State<_PlaylistButton> {
|
|||||||
// TextStyle(color: Colors.white)
|
// TextStyle(color: Colors.white)
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
data.item2.episodes.first.title,
|
data.item2.title,
|
||||||
maxLines: 2,
|
maxLines: 2,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
overflow: TextOverflow.fade,
|
overflow: TextOverflow.fade,
|
||||||
|
@ -56,6 +56,7 @@ class _PlaylistHomeState extends State<PlaylistHome> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final s = context.s;
|
||||||
return AnnotatedRegion<SystemUiOverlayStyle>(
|
return AnnotatedRegion<SystemUiOverlayStyle>(
|
||||||
value: SystemUiOverlayStyle(
|
value: SystemUiOverlayStyle(
|
||||||
systemNavigationBarIconBrightness:
|
systemNavigationBarIconBrightness:
|
||||||
@ -66,6 +67,12 @@ class _PlaylistHomeState extends State<PlaylistHome> {
|
|||||||
child: Scaffold(
|
child: Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
leading: CustomBackButton(),
|
leading: CustomBackButton(),
|
||||||
|
title: Selector<AudioPlayerNotifier, EpisodeBrief>(
|
||||||
|
selector: (_, audio) => audio.episode,
|
||||||
|
builder: (_, data, __) {
|
||||||
|
return Text(data?.title ?? '', maxLines: 1);
|
||||||
|
},
|
||||||
|
),
|
||||||
backgroundColor: context.scaffoldBackgroundColor,
|
backgroundColor: context.scaffoldBackgroundColor,
|
||||||
),
|
),
|
||||||
body: Column(
|
body: Column(
|
||||||
@ -126,23 +133,58 @@ class _PlaylistHomeState extends State<PlaylistHome> {
|
|||||||
})
|
})
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
data.item4 != null
|
if (data.item2)
|
||||||
? Padding(
|
Selector<AudioPlayerNotifier,
|
||||||
|
Tuple3<bool, double, String>>(
|
||||||
|
selector: (_, audio) => Tuple3(
|
||||||
|
audio.buffering,
|
||||||
|
(audio.backgroundAudioDuration -
|
||||||
|
audio.backgroundAudioPosition) /
|
||||||
|
1000,
|
||||||
|
audio.remoteErrorMessage),
|
||||||
|
builder: (_, data, __) {
|
||||||
|
return Padding(
|
||||||
padding: const EdgeInsets.symmetric(
|
padding: const EdgeInsets.symmetric(
|
||||||
horizontal: 20.0),
|
horizontal: 10),
|
||||||
child: Text(data.item4.title, maxLines: 1),
|
child: data.item3 != null
|
||||||
)
|
? Text(data.item3,
|
||||||
: Center(),
|
style: const TextStyle(
|
||||||
|
color: Color(0xFFFF0000)))
|
||||||
|
: data.item1
|
||||||
|
? Text(
|
||||||
|
s.buffering,
|
||||||
|
style: TextStyle(
|
||||||
|
color: context.accentColor),
|
||||||
|
)
|
||||||
|
: Text(
|
||||||
|
s.timeLeft((data.item2)
|
||||||
|
.toInt()
|
||||||
|
.toTime ??
|
||||||
|
''),
|
||||||
|
maxLines: 2,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
)
|
||||||
],
|
],
|
||||||
)),
|
)),
|
||||||
data.item3 != null
|
data.item3 != null
|
||||||
? ClipRRect(
|
? ClipRRect(
|
||||||
borderRadius: BorderRadius.circular(10),
|
borderRadius: BorderRadius.circular(10),
|
||||||
child: SizedBox(
|
child: InkWell(
|
||||||
width: 80,
|
onTap: () {
|
||||||
height: 80,
|
if (running) {
|
||||||
child:
|
context
|
||||||
Image(image: data.item4.avatarImage)),
|
.read<AudioPlayerNotifier>()
|
||||||
|
.playNext();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: SizedBox(
|
||||||
|
width: 80,
|
||||||
|
height: 80,
|
||||||
|
child:
|
||||||
|
Image(image: data.item4.avatarImage)),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
: Container(
|
: Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
@ -214,11 +256,13 @@ class __QueueState extends State<_Queue> {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final s = context.s;
|
final s = context.s;
|
||||||
return Selector<AudioPlayerNotifier, Tuple2<Playlist, bool>>(
|
return Selector<AudioPlayerNotifier, Tuple3<Playlist, bool, EpisodeBrief>>(
|
||||||
selector: (_, audio) => Tuple2(audio.playlist, audio.playerRunning),
|
selector: (_, audio) =>
|
||||||
|
Tuple3(audio.playlist, audio.playerRunning, audio.episode),
|
||||||
builder: (_, data, __) {
|
builder: (_, data, __) {
|
||||||
var episodes = data.item1.episodes.toSet().toList();
|
var episodes = data.item1.episodes.toSet().toList();
|
||||||
var queue = data.item1;
|
var queue = data.item1;
|
||||||
|
var running = data.item2;
|
||||||
return queue.name == 'Queue'
|
return queue.name == 'Queue'
|
||||||
? ReorderableListView(
|
? ReorderableListView(
|
||||||
onReorder: (oldIndex, newIndex) {
|
onReorder: (oldIndex, newIndex) {
|
||||||
@ -258,6 +302,8 @@ class __QueueState extends State<_Queue> {
|
|||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
final episode = queue.episodes[index];
|
final episode = queue.episodes[index];
|
||||||
final c = episode.backgroudColor(context);
|
final c = episode.backgroudColor(context);
|
||||||
|
final isPlaying =
|
||||||
|
data.item3 != null && data.item3 == episode;
|
||||||
return SizedBox(
|
return SizedBox(
|
||||||
height: 90.0,
|
height: 90.0,
|
||||||
child: Column(
|
child: Column(
|
||||||
@ -265,11 +311,15 @@ class __QueueState extends State<_Queue> {
|
|||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Expanded(
|
Expanded(
|
||||||
child: ListTile(
|
child: ListTile(
|
||||||
|
tileColor:
|
||||||
|
isPlaying ? context.primaryColorDark : null,
|
||||||
contentPadding: EdgeInsets.symmetric(vertical: 8),
|
contentPadding: EdgeInsets.symmetric(vertical: 8),
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
await context
|
if (!isPlaying) {
|
||||||
.read<AudioPlayerNotifier>()
|
await context
|
||||||
.episodeLoad(episode);
|
.read<AudioPlayerNotifier>()
|
||||||
|
.loadEpisodeFromPlaylist(episode);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
title: Container(
|
title: Container(
|
||||||
padding: EdgeInsets.fromLTRB(0, 5.0, 20.0, 5.0),
|
padding: EdgeInsets.fromLTRB(0, 5.0, 20.0, 5.0),
|
||||||
@ -284,7 +334,8 @@ class __QueueState extends State<_Queue> {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
Icon(Icons.unfold_more, color: c),
|
// Icon(Icons.unfold_more, color: c),
|
||||||
|
SizedBox(width: 24),
|
||||||
CircleAvatar(
|
CircleAvatar(
|
||||||
backgroundColor: c.withOpacity(0.5),
|
backgroundColor: c.withOpacity(0.5),
|
||||||
backgroundImage: episode.avatarImage),
|
backgroundImage: episode.avatarImage),
|
||||||
@ -323,7 +374,18 @@ class __QueueState extends State<_Queue> {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
//trailing: Icon(Icons.menu),
|
trailing: isPlaying && running
|
||||||
|
? Container(
|
||||||
|
height: 20,
|
||||||
|
width: 20,
|
||||||
|
margin:
|
||||||
|
EdgeInsets.symmetric(horizontal: 10),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
shape: BoxShape.circle,
|
||||||
|
),
|
||||||
|
child: WaveLoader(
|
||||||
|
color: context.accentColor))
|
||||||
|
: SizedBox(width: 1),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Divider(
|
Divider(
|
||||||
@ -688,7 +750,14 @@ class __PlaylistsState extends State<_Playlists> {
|
|||||||
style: context.textTheme.headline6,
|
style: context.textTheme.headline6,
|
||||||
),
|
),
|
||||||
Text('${queue.episodes.length} episodes'),
|
Text('${queue.episodes.length} episodes'),
|
||||||
OutlinedButton(
|
TextButton(
|
||||||
|
style: OutlinedButton.styleFrom(
|
||||||
|
side: BorderSide(
|
||||||
|
color: context.primaryColorDark),
|
||||||
|
primary: context.accentColor,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.all(
|
||||||
|
Radius.circular(100)))),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
context
|
context
|
||||||
.read<AudioPlayerNotifier>()
|
.read<AudioPlayerNotifier>()
|
||||||
@ -738,11 +807,11 @@ class __PlaylistsState extends State<_Playlists> {
|
|||||||
),
|
),
|
||||||
title: Text(data[index].name),
|
title: Text(data[index].name),
|
||||||
subtitle: Text(episodeList.isNotEmpty
|
subtitle: Text(episodeList.isNotEmpty
|
||||||
? s.episode(data[index].episodeList.length)
|
? '${data[index].episodeList.length} episodes'
|
||||||
: '0 episode'),
|
: '0 episode'),
|
||||||
trailing: IconButton(
|
trailing: IconButton(
|
||||||
splashRadius: 20,
|
splashRadius: 20,
|
||||||
icon: Icon(Icons.play_arrow),
|
icon: Icon(LineIcons.play_circle_solid, size: 30),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
context
|
context
|
||||||
.read<AudioPlayerNotifier>()
|
.read<AudioPlayerNotifier>()
|
||||||
|
@ -269,6 +269,7 @@ class AudioPlayerNotifier extends ChangeNotifier {
|
|||||||
await _getAutoPlay();
|
await _getAutoPlay();
|
||||||
|
|
||||||
var state = await _playerStateStorage.getPlayerState();
|
var state = await _playerStateStorage.getPlayerState();
|
||||||
|
print(state.toString());
|
||||||
if (state[0] != '') {
|
if (state[0] != '') {
|
||||||
_playlist = _playlists.firstWhere((p) => p.id == state[0],
|
_playlist = _playlists.firstWhere((p) => p.id == state[0],
|
||||||
orElse: () => _playlists.first);
|
orElse: () => _playlists.first);
|
||||||
@ -306,7 +307,7 @@ class AudioPlayerNotifier extends ChangeNotifier {
|
|||||||
|
|
||||||
Future<void> playlistLoad(Playlist playlist) async {
|
Future<void> playlistLoad(Playlist playlist) async {
|
||||||
var p = playlist;
|
var p = playlist;
|
||||||
if(playlist.name != 'Queue') {
|
if (playlist.name != 'Queue') {
|
||||||
await updatePlaylist(p, updateEpisodes: true);
|
await updatePlaylist(p, updateEpisodes: true);
|
||||||
}
|
}
|
||||||
_playlist = p;
|
_playlist = p;
|
||||||
@ -337,6 +338,12 @@ class AudioPlayerNotifier extends ChangeNotifier {
|
|||||||
final history = PlayHistory(_episode.title, _episode.enclosureUrl,
|
final history = PlayHistory(_episode.title, _episode.enclosureUrl,
|
||||||
backgroundAudioPosition ~/ 1000, seekSliderValue);
|
backgroundAudioPosition ~/ 1000, seekSliderValue);
|
||||||
await _dbHelper.saveHistory(history);
|
await _dbHelper.saveHistory(history);
|
||||||
|
if (_playlist.name != 'Queue') {
|
||||||
|
AudioService.customAction('setIsQueue', true);
|
||||||
|
AudioService.customAction('changeQueue', [
|
||||||
|
for (var e in _queue.episodes) jsonEncode(e.toMediaItem().toJson())
|
||||||
|
]);
|
||||||
|
}
|
||||||
await AudioService.addQueueItemAt(episodeNew.toMediaItem(), 0);
|
await AudioService.addQueueItemAt(episodeNew.toMediaItem(), 0);
|
||||||
if (startPosition > 0) {
|
if (startPosition > 0) {
|
||||||
await AudioService.seekTo(Duration(milliseconds: startPosition));
|
await AudioService.seekTo(Duration(milliseconds: startPosition));
|
||||||
@ -361,6 +368,13 @@ class AudioPlayerNotifier extends ChangeNotifier {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> loadEpisodeFromPlaylist(EpisodeBrief episode) async {
|
||||||
|
if (_playlist.episodes.contains(episode)) {
|
||||||
|
var index = _playlist.episodes.indexOf(episode);
|
||||||
|
await AudioService.customAction('changeIndex', index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> _startAudioService(playlist,
|
Future<void> _startAudioService(playlist,
|
||||||
{int index = 0, int position = 0}) async {
|
{int index = 0, int position = 0}) async {
|
||||||
_stopOnComplete = false;
|
_stopOnComplete = false;
|
||||||
@ -516,7 +530,7 @@ class AudioPlayerNotifier extends ChangeNotifier {
|
|||||||
_lastPostion ~/ 1000, _seekSliderValue);
|
_lastPostion ~/ 1000, _seekSliderValue);
|
||||||
await _dbHelper.saveHistory(history);
|
await _dbHelper.saveHistory(history);
|
||||||
}
|
}
|
||||||
_episode = null;
|
//_episode = null;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -1019,7 +1033,7 @@ class AudioPlayerTask extends BackgroundAudioTask {
|
|||||||
_skipState = AudioProcessingState.skippingToNext;
|
_skipState = AudioProcessingState.skippingToNext;
|
||||||
_playing = false;
|
_playing = false;
|
||||||
await _audioPlayer.stop();
|
await _audioPlayer.stop();
|
||||||
AudioServiceBackground.sendCustomEvent(_queue.first.title);
|
AudioServiceBackground.sendCustomEvent(mediaItem.title);
|
||||||
if (_isQueue) {
|
if (_isQueue) {
|
||||||
if (_queue.length > 0) {
|
if (_queue.length > 0) {
|
||||||
_queue.removeAt(0);
|
_queue.removeAt(0);
|
||||||
@ -1225,12 +1239,17 @@ class AudioPlayerTask extends BackgroundAudioTask {
|
|||||||
break;
|
break;
|
||||||
case 'changeQueue':
|
case 'changeQueue':
|
||||||
await _changeQueue(argument);
|
await _changeQueue(argument);
|
||||||
|
break;
|
||||||
|
case 'changeIndex':
|
||||||
|
await _changeIndex(argument);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future _changeQueue(List<dynamic> items) async {
|
Future _changeQueue(List<dynamic> items) async {
|
||||||
var queue = [for (var i in items) MediaItem.fromJson(json.decode(i))];
|
var queue = [for (var i in items) MediaItem.fromJson(json.decode(i))];
|
||||||
await _audioPlayer.stop();
|
await _audioPlayer.stop();
|
||||||
|
AudioServiceBackground.sendCustomEvent(mediaItem.title);
|
||||||
_queue.clear();
|
_queue.clear();
|
||||||
_queue.addAll(queue);
|
_queue.addAll(queue);
|
||||||
_index = 0;
|
_index = 0;
|
||||||
@ -1242,6 +1261,17 @@ class AudioPlayerTask extends BackgroundAudioTask {
|
|||||||
_playFromStart();
|
_playFromStart();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future _changeIndex(int index) async {
|
||||||
|
await _audioPlayer.stop();
|
||||||
|
AudioServiceBackground.sendCustomEvent(mediaItem.title);
|
||||||
|
_index = index;
|
||||||
|
await AudioServiceBackground.setMediaItem(mediaItem);
|
||||||
|
await _audioPlayer.setUrl(mediaItem.id, cacheMax: _cacheMax);
|
||||||
|
var duration = await _audioPlayer.durationFuture ?? Duration.zero;
|
||||||
|
AudioServiceBackground.setMediaItem(mediaItem.copyWith(duration: duration));
|
||||||
|
_playFromStart();
|
||||||
|
}
|
||||||
|
|
||||||
Future _setSkipSilence(bool boo) async {
|
Future _setSkipSilence(bool boo) async {
|
||||||
await _audioPlayer.setSkipSilence(boo);
|
await _audioPlayer.setSkipSilence(boo);
|
||||||
var duration = await _audioPlayer.durationFuture ?? Duration.zero;
|
var duration = await _audioPlayer.durationFuture ?? Duration.zero;
|
||||||
|
@ -61,7 +61,6 @@ class Playlist extends Equatable {
|
|||||||
episodes.clear();
|
episodes.clear();
|
||||||
if (episodeList.isNotEmpty) {
|
if (episodeList.isNotEmpty) {
|
||||||
for (var url in episodeList) {
|
for (var url in episodeList) {
|
||||||
print(url);
|
|
||||||
var episode = await _dbHelper.getRssItemWithUrl(url);
|
var episode = await _dbHelper.getRssItemWithUrl(url);
|
||||||
if (episode != null) episodes.add(episode);
|
if (episode != null) episodes.add(episode);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user