diff --git a/lib/components/Artist/ArtistProfile.dart b/lib/components/Artist/ArtistProfile.dart index 0a3751f0..3e589617 100644 --- a/lib/components/Artist/ArtistProfile.dart +++ b/lib/components/Artist/ArtistProfile.dart @@ -4,12 +4,10 @@ import 'package:flutter/services.dart'; import 'package:provider/provider.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/components/Album/AlbumCard.dart'; -import 'package:spotube/components/Album/AlbumView.dart'; import 'package:spotube/components/Artist/ArtistAlbumView.dart'; import 'package:spotube/components/Artist/ArtistCard.dart'; -import 'package:spotube/components/Shared/LinkText.dart'; import 'package:spotube/components/Shared/PageWindowTitleBar.dart'; -import 'package:spotube/helpers/artists-to-clickable-artists.dart'; +import 'package:spotube/components/Shared/TracksTableView.dart'; import 'package:spotube/helpers/readable-number.dart'; import 'package:spotube/helpers/zero-pad-num-str.dart'; import 'package:spotube/provider/Playback.dart'; @@ -162,81 +160,49 @@ class _ArtistProfileState extends State { "Top Tracks", style: Theme.of(context).textTheme.headline4, ), - IconButton( - icon: Icon(isPlaylistPlaying - ? Icons.stop_circle_rounded - : Icons.play_circle_filled_rounded), - color: Theme.of(context).primaryColor, - onPressed: trackSnapshot.hasData - ? () => - playPlaylist(trackSnapshot.data!.toList()) - : null, + Container( + margin: const EdgeInsets.symmetric(horizontal: 5), + decoration: BoxDecoration( + color: Theme.of(context).primaryColor, + borderRadius: BorderRadius.circular(50), + ), + child: IconButton( + icon: Icon(isPlaylistPlaying + ? Icons.stop_rounded + : Icons.play_arrow_rounded), + color: Colors.white, + onPressed: trackSnapshot.hasData + ? () => + playPlaylist(trackSnapshot.data!.toList()) + : null, + ), ) ], ), - ...trackSnapshot.data?.map((track) { + ...trackSnapshot.data + ?.toList() + .asMap() + .entries + .map((track) { String duration = - "${track.duration?.inMinutes.remainder(60)}:${zeroPadNumStr(track.duration?.inSeconds.remainder(60) ?? 0)}"; - return Row( - children: [ - if (track.album != null && - track.album!.images!.isNotEmpty) - Padding( - padding: const EdgeInsets.all(8.0), - child: ClipRRect( - borderRadius: const BorderRadius.all( - Radius.circular(5)), - child: CachedNetworkImage( - placeholder: (context, url) { - return Container( - height: 40, - width: 40, - color: Colors.green[300], - ); - }, - imageUrl: - track.album!.images!.last.url!, - maxHeightDiskCache: 40, - maxWidthDiskCache: 40, - ), - ), - ), - Expanded( - child: Column( - crossAxisAlignment: - CrossAxisAlignment.start, - children: [ - Text( - track.name ?? "", - style: const TextStyle( - fontWeight: FontWeight.bold, - fontSize: 17, - ), - overflow: TextOverflow.ellipsis, - ), - artistsToClickableArtists( - track.artists ?? []), - ], - ), - ), - Expanded( - child: Row( - children: [ - LinkText( - track.album!.name!, - MaterialPageRoute( - builder: (context) => - AlbumView(track.album!), - ), - ), - ], - ), - ), - const SizedBox(width: 10), - Text(duration) - ], + "${track.value.duration?.inMinutes.remainder(60)}:${zeroPadNumStr(track.value.duration?.inSeconds.remainder(60) ?? 0)}"; + String? thumbnailUrl = track.value.album != null && + track.value.album!.images!.isNotEmpty + ? track.value.album!.images!.last.url! + : null; + return TracksTableView.buildTrackTile( + context, + playback, + duration: duration, + track: track, + thumbnailUrl: thumbnailUrl, + onTrackPlayButtonPressed: (currentTrack) => + playPlaylist( + trackSnapshot.data!.toList(), + currentTrack: track.value, + ), ); - }).toList() ?? + }) ?? [], ]); }, diff --git a/lib/components/Shared/TracksTableView.dart b/lib/components/Shared/TracksTableView.dart index aab11dce..c5a30543 100644 --- a/lib/components/Shared/TracksTableView.dart +++ b/lib/components/Shared/TracksTableView.dart @@ -14,154 +14,152 @@ class TracksTableView extends StatelessWidget { const TracksTableView(this.tracks, {Key? key, this.onTrackPlayButtonPressed}) : super(key: key); - List trackToTableRow( - BuildContext context, Playback playback, List tracks) { - return tracks.asMap().entries.map((track) { - String? thumbnailUrl = (track.value.album?.images?.isNotEmpty ?? false) - ? track.value.album?.images?.last.url - : null; - String duration = - "${track.value.duration?.inMinutes.remainder(60)}:${zeroPadNumStr(track.value.duration?.inSeconds.remainder(60) ?? 0)}"; - return (TableRow( - children: [ - TableCell( - child: Padding( + static Widget buildTrackTile( + BuildContext context, + Playback playback, { + required MapEntry track, + required String duration, + String? thumbnailUrl, + final void Function(Track currentTrack)? onTrackPlayButtonPressed, + }) { + return Row( + children: [ + SizedBox( + height: 20, + width: 25, + child: Text( + (track.key + 1).toString(), + textAlign: TextAlign.center, + ), + ), + if (thumbnailUrl != null) + Padding( padding: const EdgeInsets.all(8.0), - child: Text( - (track.key + 1).toString(), - textAlign: TextAlign.center, - ), - )), - TableCell( - child: Row( - children: [ - IconButton( - icon: Icon( - playback.currentTrack?.id != null && - playback.currentTrack?.id == track.value.id - ? Icons.pause_circle_rounded - : Icons.play_circle_rounded, - color: Theme.of(context).primaryColor, - ), - onPressed: () => onTrackPlayButtonPressed?.call( - track.value, - ), - ), - if (thumbnailUrl != null) - Padding( - padding: const EdgeInsets.all(8.0), - child: ClipRRect( - borderRadius: const BorderRadius.all(Radius.circular(5)), - child: CachedNetworkImage( - placeholder: (context, url) { - return Container( - height: 40, - width: 40, - color: Colors.green[300], - ); - }, - imageUrl: thumbnailUrl, - maxHeightDiskCache: 40, - maxWidthDiskCache: 40, - ), - ), - ), - const SizedBox(width: 10), - Flexible( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - track.value.name ?? "", - style: const TextStyle( - fontWeight: FontWeight.bold, - fontSize: 17, - ), - overflow: TextOverflow.ellipsis, - ), - artistsToClickableArtists(track.value.artists ?? []), - ], - ), - ), - ], + child: ClipRRect( + borderRadius: const BorderRadius.all(Radius.circular(5)), + child: CachedNetworkImage( + placeholder: (context, url) { + return Container( + height: 40, + width: 40, + color: Colors.green[300], + ); + }, + imageUrl: thumbnailUrl, + maxHeightDiskCache: 40, + maxWidthDiskCache: 40, + ), ), ), - TableCell( - child: Padding( - padding: const EdgeInsets.all(8.0), - child: LinkText( - track.value.album?.name ?? "", + IconButton( + icon: Icon( + playback.currentTrack?.id != null && + playback.currentTrack?.id == track.value.id + ? Icons.pause_circle_rounded + : Icons.play_circle_rounded, + color: Theme.of(context).primaryColor, + ), + onPressed: () => onTrackPlayButtonPressed?.call( + track.value, + ), + ), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + track.value.name ?? "", + style: const TextStyle( + fontWeight: FontWeight.bold, + fontSize: 17, + ), + overflow: TextOverflow.ellipsis, + ), + artistsToClickableArtists(track.value.artists ?? []), + ], + ), + ), + Expanded( + child: Row( + children: [ + LinkText( + track.value.album!.name!, MaterialPageRoute( builder: (context) => AlbumView(track.value.album!), ), overflow: TextOverflow.ellipsis, ), - ), + ], ), - TableCell( - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Text( - duration, - textAlign: TextAlign.center, - overflow: TextOverflow.ellipsis, - ), - ), - ) - ], - )); - }).toList(); + ), + const SizedBox(width: 10), + Text(duration), + const SizedBox(width: 10), + ], + ); } @override Widget build(BuildContext context) { Playback playback = context.watch(); - TextStyle tableHeadStyle = const TextStyle(fontWeight: FontWeight.bold, fontSize: 16); return Expanded( child: Scrollbar( child: ListView( children: [ - SingleChildScrollView( - child: Table( - columnWidths: const { - 0: FixedColumnWidth(40), - 1: FlexColumnWidth(), - 2: FlexColumnWidth(), - 3: FixedColumnWidth(45), - }, - children: [ - TableRow( + Row( + children: [ + Padding( + padding: const EdgeInsets.all(8.0), + child: Text( + "#", + textAlign: TextAlign.center, + style: tableHeadStyle, + ), + ), + Expanded( + child: Row( children: [ - TableCell( - child: Text( - "#", - textAlign: TextAlign.center, - style: tableHeadStyle, - )), - TableCell( - child: Text( + Text( "Title", style: tableHeadStyle, - )), - TableCell( - child: Text( - "Album", - style: tableHeadStyle, - )), - TableCell( - child: Text( - "Time", - textAlign: TextAlign.center, - style: tableHeadStyle, - )), + overflow: TextOverflow.ellipsis, + ), ], ), - ...trackToTableRow(context, playback, tracks), - ], - ), + ), + // used alignment of this table-head + const SizedBox(width: 100), + Expanded( + child: Row( + children: [ + Text( + "Album", + overflow: TextOverflow.ellipsis, + style: tableHeadStyle, + ), + ], + ), + ), + const SizedBox(width: 10), + Text("Time", style: tableHeadStyle), + const SizedBox(width: 10), + ], ), + ...tracks.asMap().entries.map((track) { + String? thumbnailUrl = + (track.value.album?.images?.isNotEmpty ?? false) + ? track.value.album?.images?.last.url + : null; + String duration = + "${track.value.duration?.inMinutes.remainder(60)}:${zeroPadNumStr(track.value.duration?.inSeconds.remainder(60) ?? 0)}"; + return buildTrackTile(context, playback, + track: track, + duration: duration, + thumbnailUrl: thumbnailUrl, + onTrackPlayButtonPressed: onTrackPlayButtonPressed); + }).toList() ], ), ),