From 25e64f67e03754d47d5730a17224a6192b8d1ffe Mon Sep 17 00:00:00 2001 From: Pierre Hubert Date: Sat, 1 Oct 2022 15:50:49 +0200 Subject: [PATCH] WIP new UI --- lib/api.dart | 2 +- lib/ui/music_player.dart | 314 ++++++++++++++++++++++++++------------- lib/ui/player_app.dart | 2 +- 3 files changed, 212 insertions(+), 106 deletions(-) diff --git a/lib/api.dart b/lib/api.dart index d347ba7..65e5162 100644 --- a/lib/api.dart +++ b/lib/api.dart @@ -30,7 +30,7 @@ typedef MusicsList = List; class API { /// Get the list of music static Future getList() async { - final response = await Dio().get(config.apiURL + "/list", + final response = await Dio().get("${config.apiURL}/list", options: Options(headers: {"Token": config.apiToken})); if (response.statusCode != 200) { diff --git a/lib/ui/music_player.dart b/lib/ui/music_player.dart index 01ce222..287e104 100644 --- a/lib/ui/music_player.dart +++ b/lib/ui/music_player.dart @@ -156,82 +156,97 @@ class _MusicPlayerState extends State { @override Widget build(BuildContext context) { - return LayoutBuilder( - builder: (context, constraints) { - final mainAreaWidth = - constraints.maxWidth - (_showPlaylist ? playlistWidth : 0); + if (!_showPlaylist) { + return _playerWithoutPlaylistPane(); + } else { + return _playerWithPlaylistPane(); + } + } - return fluent.Row( - children: [ - SizedBox( - width: mainAreaWidth, - child: Stack( - children: [ - // Background image - CoverImage( - music: currMusic, - width: mainAreaWidth, - height: constraints.maxHeight, - fit: BoxFit.cover, - ), + Widget _playerWithoutPlaylistPane() => LayoutBuilder( + builder: (context, constraints) { + final mainAreaWidth = constraints.maxWidth; - // Blur background image - ClipRRect( - // Clip it cleanly. - child: BackdropFilter( - filter: ImageFilter.blur(sigmaX: 10, sigmaY: 10), - child: Container( - color: Colors.black.withOpacity(0.8), - alignment: Alignment.center, - child: SizedBox( - width: mainAreaWidth, - height: constraints.maxHeight, + return fluent.Row( + children: [ + SizedBox( + width: mainAreaWidth, + child: Stack( + children: [ + // Background image + CoverImage( + music: currMusic, + width: mainAreaWidth, + height: constraints.maxHeight, + fit: BoxFit.cover, + ), + + // Blur background image + ClipRRect( + // Clip it cleanly. + child: BackdropFilter( + filter: ImageFilter.blur(sigmaX: 10, sigmaY: 10), + child: Container( + color: Colors.black.withOpacity(0.8), + alignment: Alignment.center, + child: SizedBox( + width: mainAreaWidth, + height: constraints.maxHeight, + ), ), ), ), - ), - fluent.SizedBox( - width: mainAreaWidth, - child: _buildPlayerWidget(), - ), + fluent.SizedBox( + width: mainAreaWidth, + child: _buildPlayerWidget(), + ), - Positioned( - top: 10, - right: 10, - child: fluent.Row( - children: [ - _buildToggleListButton(), - ], - )), + Positioned( + top: 10, + right: 10, + child: fluent.Row( + children: [ + _buildToggleListButton(), + ], + )), - Positioned( - bottom: 10, - right: 10, - child: fluent.Row( - children: [ - _buildDownloadTrackButton(), - const SizedBox(width: 10), - _buildAboutButton(), - ], - )), - ], + Positioned( + bottom: 10, + right: 10, + child: fluent.Row( + children: [ + _buildDownloadTrackButton(), + const SizedBox(width: 10), + _buildAboutButton(), + ], + )), + ], + ), ), - ), + ], + ); + }, + ); - // Playlist - _showPlaylist - ? SizedBox( - width: playlistWidth, - height: constraints.maxHeight, - child: _buildPlaylistPane(), - ) - : Container(), - ], - ); - }, - ); - } + Widget _playerWithPlaylistPane() => LayoutBuilder( + builder: (context, constraints) { + const double playerSize = 100; + return Column( + children: [ + fluent.SizedBox( + height: constraints.maxHeight - playerSize, + child: _buildPlaylistPane(), + ), + fluent.SizedBox( + height: playerSize, + width: constraints.maxWidth, + child: _buildSmallPlayerWidget(constraints.maxWidth), + ), + ], + ); + }, + ); Widget _buildPlayerWidget() => fluent.Center( child: SizedBox( @@ -264,45 +279,133 @@ class _MusicPlayerState extends State { children: [ DurationText(_position), const SizedBox(width: 15), - Flexible( - child: fluent.Slider( - max: _duration?.inSeconds as double? ?? 0, - value: _position?.inSeconds as double? ?? 0, - onChanged: (d) => - _updatePosition(Duration(seconds: d.toInt())), - label: _position?.formatted, - ), - ), + _buildProgressBar(), const SizedBox(width: 15), DurationText(_duration), ], ), const fluent.SizedBox(height: 40), - fluent.Row( - children: [ - IconButton( - icon: const PlayerIcon(fluent.FluentIcons.previous), - onPressed: currMusicPos == 0 ? null : _playPrevious, - ), - const Spacer(), - IconButton( - icon: PlayerIcon(_isPlaying - ? fluent.FluentIcons.pause - : fluent.FluentIcons.play), - onPressed: _isPlaying ? _pause : _play, - ), - const Spacer(), - IconButton( - icon: const PlayerIcon(fluent.FluentIcons.next), - onPressed: _playNext, - ), - ], - ) + _buildPlayersIcons(), ], ), ), ); + Widget _buildSmallPlayerWidget(double width) => fluent.Container( + color: Colors.black, + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + fluent.ClipRect( + child: Flexible( + flex: 1, + child: ConstrainedBox( + constraints: + BoxConstraints(maxWidth: min(350, width * (1 / 2))), + child: Row( + children: [ + RoundedImage( + child: CoverImage( + music: currMusic, + width: 80, + height: 80, + backgroundColor: Colors.black, + fit: BoxFit.cover, + ), + ), + // Artist area + const SizedBox(width: 10), + fluent.ClipRect( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + currMusic.title, + style: const TextStyle(fontSize: 22), + overflow: TextOverflow.ellipsis, + ), + Text( + currMusic.artist, + textAlign: TextAlign.start, + overflow: TextOverflow.ellipsis, + ), + ], + ), + ) + ], + ), + ), + ), + ), + const Spacer(), + Flexible( + child: ConstrainedBox( + constraints: + BoxConstraints(maxWidth: min(500, width * (1 / 4))), + child: Column( + children: [ + fluent.Row( + children: [ + DurationText(_position), + const SizedBox(width: 20), + _buildProgressBar(), + const SizedBox(width: 20), + DurationText(_duration), + ], + ), + const SizedBox(height: 5), + _buildPlayersIcons(25), + ], + )), + ), + const Spacer(), + _buildToggleListButton() + ], + ), + ), + ); + + Widget _buildPlayersIcons([double? size]) => fluent.Row( + children: [ + IconButton( + icon: PlayerIcon( + fluent.FluentIcons.previous, + size: size, + ), + onPressed: currMusicPos == 0 ? null : _playPrevious, + ), + const Spacer(), + IconButton( + icon: PlayerIcon( + _isPlaying ? fluent.FluentIcons.pause : fluent.FluentIcons.play, + size: size, + ), + onPressed: _isPlaying ? _pause : _play, + ), + const Spacer(), + IconButton( + icon: PlayerIcon( + fluent.FluentIcons.next, + size: size, + ), + onPressed: _playNext, + ), + ], + ); + + Widget _buildProgressBar() => Flexible( + child: fluent.Slider( + max: _duration?.inSeconds as double? ?? 0, + value: _position?.inSeconds as double? ?? 0, + onChanged: (d) => _updatePosition(Duration(seconds: d.toInt())), + label: _position?.formatted, + ), + ); + Widget _buildDownloadTrackButton() => fluent.Button( onPressed: () => launchUrlString(currMusic.musicURL, webOnlyWindowName: "_blank"), @@ -364,13 +467,15 @@ class _MusicPlayerState extends State { itemCount: (_filteredList ?? widget.musicsList).length, ), ), - ListTile( - leading: fluent.ToggleSwitch( - checked: _playFilteredMusics, - onChanged: (v) => setState(() => _playFilteredMusics = v), - ), - title: const Text("Play only filtered musics"), - ) + _filteredList == null + ? Container() + : ListTile( + leading: fluent.ToggleSwitch( + checked: _playFilteredMusics, + onChanged: (v) => setState(() => _playFilteredMusics = v), + ), + title: const Text("Play only filtered musics"), + ) ], ); } @@ -378,11 +483,12 @@ class _MusicPlayerState extends State { class PlayerIcon extends StatelessWidget { final IconData icon; + final double? size; - const PlayerIcon(this.icon, {Key? key}) : super(key: key); + const PlayerIcon(this.icon, {Key? key, this.size}) : super(key: key); @override - Widget build(BuildContext context) => Icon(icon, size: 35); + Widget build(BuildContext context) => Icon(icon, size: size ?? 35); } class DurationText extends StatelessWidget { diff --git a/lib/ui/player_app.dart b/lib/ui/player_app.dart index dd083f5..735f9fc 100644 --- a/lib/ui/player_app.dart +++ b/lib/ui/player_app.dart @@ -20,11 +20,11 @@ class PlayerApp extends StatelessWidget { brightness: Brightness.dark, ), home: fluent.FluentTheme( - child: const AppHome(), data: fluent.ThemeData( iconTheme: const IconThemeData(color: Colors.white), brightness: fluent.Brightness.dark, ), + child: const AppHome(), ), ); }