From d12ea48b97596205d6309012d561ce83e5cbc9c1 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Mon, 11 Sep 2023 11:05:42 +0600 Subject: [PATCH] feat: show loading indicator on play track --- lib/components/library/user_local_tracks.dart | 10 ++-- .../track_collection_view.dart | 4 +- .../shared/track_table/track_tile.dart | 52 ++++++++++++------- .../shared/track_table/tracks_table_view.dart | 14 ++--- lib/pages/album/album.dart | 8 +-- lib/pages/artist/artist.dart | 2 +- lib/pages/playlist/playlist.dart | 14 ++--- 7 files changed, 57 insertions(+), 47 deletions(-) diff --git a/lib/components/library/user_local_tracks.dart b/lib/components/library/user_local_tracks.dart index a36be2830..16692462e 100644 --- a/lib/components/library/user_local_tracks.dart +++ b/lib/components/library/user_local_tracks.dart @@ -131,7 +131,7 @@ final localTracksProvider = FutureProvider>((ref) async { class UserLocalTracks extends HookConsumerWidget { const UserLocalTracks({Key? key}) : super(key: key); - void playLocalTracks( + Future playLocalTracks( WidgetRef ref, List tracks, { LocalTrack? currentTrack, @@ -203,10 +203,10 @@ class UserLocalTracks extends HookConsumerWidget { const SizedBox(width: 10), FilledButton( onPressed: trackSnapshot.value != null - ? () { + ? () async { if (trackSnapshot.value?.isNotEmpty == true) { if (!isPlaylistPlaying) { - playLocalTracks( + await playLocalTracks( ref, trackSnapshot.value!, ); @@ -295,8 +295,8 @@ class UserLocalTracks extends HookConsumerWidget { index: index, track: track, userPlaylist: false, - onTap: () { - playLocalTracks( + onTap: () async { + await playLocalTracks( ref, sortedTracks, currentTrack: track, diff --git a/lib/components/shared/track_table/track_collection_view/track_collection_view.dart b/lib/components/shared/track_table/track_collection_view/track_collection_view.dart index 1c87d8878..14d9598fa 100644 --- a/lib/components/shared/track_table/track_collection_view/track_collection_view.dart +++ b/lib/components/shared/track_table/track_collection_view/track_collection_view.dart @@ -1,3 +1,5 @@ +import 'dart:async'; + import 'package:fl_query/fl_query.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:go_router/go_router.dart'; @@ -27,7 +29,7 @@ class TrackCollectionView extends HookConsumerWidget { final Query, T> tracksSnapshot; final String titleImage; final PlayButtonState playingState; - final void Function([Track? currentTrack]) onPlay; + final Future Function([Track? currentTrack]) onPlay; final void Function([Track? currentTrack]) onShuffledPlay; final void Function() onAddToQueue; final void Function() onShare; diff --git a/lib/components/shared/track_table/track_tile.dart b/lib/components/shared/track_table/track_tile.dart index 9fe13dcc3..757432fe8 100644 --- a/lib/components/shared/track_table/track_tile.dart +++ b/lib/components/shared/track_table/track_tile.dart @@ -1,3 +1,5 @@ +import 'dart:async'; + import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; @@ -21,7 +23,7 @@ class TrackTile extends HookConsumerWidget { final Track track; final bool selected; final ValueChanged? onChanged; - final VoidCallback? onTap; + final Future Function()? onTap; final VoidCallback? onLongPress; final bool userPlaylist; final String? playlistId; @@ -62,6 +64,10 @@ class TrackTile extends HookConsumerWidget { final isPlaying = track.id == playlist.activeTrack?.id; + final isLoading = useState(false); + + final isSelected = isPlaying || isLoading.value; + return LayoutBuilder(builder: (context, constrains) { return Listener( onPointerDown: (event) { @@ -76,11 +82,18 @@ class TrackTile extends HookConsumerWidget { ); }, child: HoverBuilder( - permanentState: isPlaying || constrains.smAndDown ? true : null, + permanentState: isSelected || constrains.smAndDown ? true : null, builder: (context, isHovering) { return ListTile( - selected: isPlaying, - onTap: onTap, + selected: isSelected, + onTap: () async { + try { + isLoading.value = true; + await onTap?.call(); + } finally { + isLoading.value = false; + } + }, onLongPress: onLongPress, enabled: !isBlackListed, contentPadding: EdgeInsets.zero, @@ -145,22 +158,23 @@ class TrackTile extends HookConsumerWidget { .copyWith(size: 26, color: Colors.white), child: AnimatedSwitcher( duration: const Duration(milliseconds: 300), - child: !isHovering - ? const SizedBox.shrink() - : isPlaying && playlist.isFetching - ? const SizedBox( - width: 26, - height: 26, - child: CircularProgressIndicator( - strokeWidth: 1.5, - color: Colors.white, - ), + child: (isPlaying && playlist.isFetching) || + isLoading.value + ? const SizedBox( + width: 26, + height: 26, + child: CircularProgressIndicator( + strokeWidth: 1.5, + color: Colors.white, + ), + ) + : isPlaying + ? Icon( + SpotubeIcons.pause, + color: theme.colorScheme.primary, ) - : isPlaying - ? Icon( - SpotubeIcons.pause, - color: theme.colorScheme.primary, - ) + : !isHovering + ? const SizedBox.shrink() : const Icon(SpotubeIcons.play), ), ), diff --git a/lib/components/shared/track_table/tracks_table_view.dart b/lib/components/shared/track_table/tracks_table_view.dart index 58d662f45..2ad6d3847 100644 --- a/lib/components/shared/track_table/tracks_table_view.dart +++ b/lib/components/shared/track_table/tracks_table_view.dart @@ -1,3 +1,5 @@ +import 'dart:async'; + import 'package:collection/collection.dart'; import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; @@ -27,7 +29,7 @@ final trackCollectionSortState = StateProvider.family((ref, _) => SortBy.none); class TracksTableView extends HookConsumerWidget { - final void Function(Track currentTrack)? onTrackPlayButtonPressed; + final Future Function(Track currentTrack)? onTrackPlayButtonPressed; final List tracks; final bool userPlaylist; final String? playlistId; @@ -58,8 +60,7 @@ class TracksTableView extends HookConsumerWidget { final downloader = ref.watch(downloadManagerProvider.notifier); final apiType = ref.watch(userPreferencesProvider.select((s) => s.youtubeApiType)); - final tableHeadStyle = - const TextStyle(fontWeight: FontWeight.bold, fontSize: 16); + const tableHeadStyle = TextStyle(fontWeight: FontWeight.bold, fontSize: 16); final selected = useState>([]); final showCheck = useState(false); @@ -297,7 +298,7 @@ class TracksTableView extends HookConsumerWidget { selected: selected.value.contains(track.id), userPlaylist: userPlaylist, playlistId: playlistId, - onTap: () { + onTap: () async { if (showCheck.value) { final alreadyChecked = selected.value.contains(track.id); if (alreadyChecked) { @@ -314,9 +315,8 @@ class TracksTableView extends HookConsumerWidget { ), ), ); - if (!isBlackListed) { - onTrackPlayButtonPressed?.call(track); - } + if (isBlackListed) return; + await onTrackPlayButtonPressed?.call(track); } }, onLongPress: () { diff --git a/lib/pages/album/album.dart b/lib/pages/album/album.dart index 84e23e8b2..a585c9e52 100644 --- a/lib/pages/album/album.dart +++ b/lib/pages/album/album.dart @@ -85,10 +85,10 @@ class AlbumPage extends HookConsumerWidget { album: album, routePath: "/album/${album.id}", bottomSpace: mediaQuery.mdAndDown, - onPlay: ([track]) { + onPlay: ([track]) async { if (tracksSnapshot.hasData) { if (!isAlbumPlaying) { - playPlaylist( + await playPlaylist( tracksSnapshot.data! .map((track) => TypeConversionUtils.simpleTrack_X_Track(track, album)) @@ -96,7 +96,7 @@ class AlbumPage extends HookConsumerWidget { ref, ); } else if (isAlbumPlaying && track != null) { - playPlaylist( + await playPlaylist( tracksSnapshot.data! .map((track) => TypeConversionUtils.simpleTrack_X_Track(track, album)) @@ -105,7 +105,7 @@ class AlbumPage extends HookConsumerWidget { ref, ); } else { - playback + await playback .removeTracks(tracksSnapshot.data!.map((track) => track.id!)); } } diff --git a/lib/pages/artist/artist.dart b/lib/pages/artist/artist.dart index 44e404233..e1bbefcb1 100644 --- a/lib/pages/artist/artist.dart +++ b/lib/pages/artist/artist.dart @@ -390,7 +390,7 @@ class ArtistPage extends HookConsumerWidget { return TrackTile( index: i, track: track, - onTap: () { + onTap: () async { playPlaylist( topTracks.toList(), currentTrack: track, diff --git a/lib/pages/playlist/playlist.dart b/lib/pages/playlist/playlist.dart index 9c852ace9..1623195b7 100644 --- a/lib/pages/playlist/playlist.dart +++ b/lib/pages/playlist/playlist.dart @@ -104,22 +104,16 @@ class PlaylistView extends HookConsumerWidget { tracksSnapshot: tracksSnapshot, description: playlist.description, isOwned: ownPlaylist, - onPlay: ([track]) { + onPlay: ([track]) async { if (tracksSnapshot.hasData) { - if (!isPlaylistPlaying) { - playPlaylist( - tracksSnapshot.data!, - ref, - currentTrack: track, - ); - } else if (isPlaylistPlaying && track != null) { - playPlaylist( + if (!isPlaylistPlaying || (isPlaylistPlaying && track != null)) { + await playPlaylist( tracksSnapshot.data!, ref, currentTrack: track, ); } else { - playlistNotifier + await playlistNotifier .removeTracks(tracksSnapshot.data!.map((e) => e.id!)); } }