From c0714ab3c8378e6c1033b483bfebb1b2ac0875d7 Mon Sep 17 00:00:00 2001 From: LittleSheep Date: Wed, 28 Aug 2024 20:34:35 +0800 Subject: [PATCH] :sparkles: Playable playlist screen --- lib/screens/player/lyrics.dart | 7 +- lib/screens/playlist/view.dart | 79 +++++++++++++++++++-- lib/shells/nav_shell.dart | 2 +- lib/widgets/lyrics/synced.dart | 2 +- lib/widgets/tracks/playlist_track_list.dart | 12 ++-- 5 files changed, 88 insertions(+), 14 deletions(-) diff --git a/lib/screens/player/lyrics.dart b/lib/screens/player/lyrics.dart index 6d5f4c0..bb3724c 100644 --- a/lib/screens/player/lyrics.dart +++ b/lib/screens/player/lyrics.dart @@ -23,10 +23,13 @@ class LyricsScreen extends StatelessWidget { ], ), bottomNavigationBar: const SizedBox( - height: 83, + height: 85, child: Material( elevation: 2, - child: BottomPlayer(usePop: true), + child: BottomPlayer( + key: Key('lyrics-page-bottom-player'), + usePop: true, + ), ), ), ), diff --git a/lib/screens/playlist/view.dart b/lib/screens/playlist/view.dart index a61e1f6..419f164 100644 --- a/lib/screens/playlist/view.dart +++ b/lib/screens/playlist/view.dart @@ -1,9 +1,14 @@ +import 'dart:math'; + import 'package:flutter/material.dart'; import 'package:gap/gap.dart'; import 'package:get/get.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:intl/intl.dart'; +import 'package:rhythm_box/providers/audio_player.dart'; +import 'package:rhythm_box/providers/history.dart'; import 'package:rhythm_box/providers/spotify.dart'; +import 'package:rhythm_box/services/audio_player/audio_player.dart'; import 'package:rhythm_box/widgets/auto_cache_image.dart'; import 'package:rhythm_box/widgets/tracks/playlist_track_list.dart'; import 'package:spotify/spotify.dart'; @@ -24,8 +29,14 @@ class PlaylistViewScreen extends StatefulWidget { class _PlaylistViewScreenState extends State { late final SpotifyProvider _spotify = Get.find(); + late final AudioPlayerProvider _playback = Get.find(); + + bool get _isCurrentPlaylist => _playlist != null + ? _playback.state.value.containsCollection(_playlist!.id!) + : false; bool _isLoading = true; + bool _isUpdating = false; Playlist? _playlist; @@ -116,15 +127,73 @@ class _PlaylistViewScreenState extends State { Wrap( spacing: 8, children: [ - ElevatedButton.icon( - icon: const Icon(Icons.play_arrow_outlined), - label: const Text('Play'), - onPressed: () {}, + Obx( + () => ElevatedButton.icon( + icon: (_isCurrentPlaylist && + _playback.isPlaying.value) + ? const Icon(Icons.pause_outlined) + : const Icon(Icons.play_arrow), + label: const Text('Play'), + onPressed: _isUpdating + ? null + : () async { + if (_isCurrentPlaylist && + _playback.isPlaying.value) { + audioPlayer.pause(); + return; + } else if (_isCurrentPlaylist && + !_playback.isPlaying.value) { + audioPlayer.resume(); + return; + } + + setState(() => _isUpdating = true); + + final tracks = (await _spotify + .api.playlists + .getTracksByPlaylistId( + widget.playlistId) + .all()) + .toList(); + + await _playback.load(tracks, + autoPlay: true); + _playback.addCollection(_playlist!.id!); + Get.find() + .addPlaylists([_playlist!]); + + setState(() => _isUpdating = false); + }, + ), ), TextButton.icon( icon: const Icon(Icons.shuffle), label: const Text('Shuffle'), - onPressed: () {}, + onPressed: _isUpdating + ? null + : () async { + setState(() => _isUpdating = true); + + audioPlayer.setShuffle(true); + + final tracks = (await _spotify.api.playlists + .getTracksByPlaylistId( + widget.playlistId) + .all()) + .toList(); + + await _playback.load( + tracks, + autoPlay: true, + initialIndex: + Random().nextInt(tracks.length), + ); + _playback.addCollection(_playlist!.id!); + Get.find() + .addPlaylists([_playlist!]); + + setState(() => _isUpdating = false); + }, ), ], ).paddingSymmetric(horizontal: 24), diff --git a/lib/shells/nav_shell.dart b/lib/shells/nav_shell.dart index 2a28e62..9295f89 100644 --- a/lib/shells/nav_shell.dart +++ b/lib/shells/nav_shell.dart @@ -36,7 +36,7 @@ class _NavShellState extends State { child: Column( mainAxisSize: MainAxisSize.min, children: [ - const BottomPlayer(), + const BottomPlayer(key: Key('app-wide-bottom-player')), const Divider(height: 0.3, thickness: 0.3), BottomNavigationBar( elevation: 0, diff --git a/lib/widgets/lyrics/synced.dart b/lib/widgets/lyrics/synced.dart index 463c86f..3e463a1 100644 --- a/lib/widgets/lyrics/synced.dart +++ b/lib/widgets/lyrics/synced.dart @@ -141,7 +141,7 @@ class _SyncedLyricsState extends State { ), ).animate(target: isActive ? 1 : 0).scale( duration: 300.ms, - begin: const Offset(1, 1), + begin: const Offset(0.9, 0.9), end: const Offset(1.3, 1.3), ); }).paddingSymmetric(horizontal: 12), diff --git a/lib/widgets/tracks/playlist_track_list.dart b/lib/widgets/tracks/playlist_track_list.dart index 8391a6b..41f0598 100644 --- a/lib/widgets/tracks/playlist_track_list.dart +++ b/lib/widgets/tracks/playlist_track_list.dart @@ -70,11 +70,13 @@ class _PlaylistTrackListState extends State { ), onTap: () { if (item == null) return; - Get.find().load( - _tracks!, - initialIndex: idx, - autoPlay: true, - ); + Get.find() + ..load( + _tracks!, + initialIndex: idx, + autoPlay: true, + ) + ..addCollection(widget.playlistId); }, ); },