fix: re-enable add to queue and play next support, favorite button query exceptions

This commit is contained in:
Kingkor Roy Tirtho 2023-05-27 21:53:56 +06:00
parent bf59570251
commit e529c79c4f
9 changed files with 87 additions and 38 deletions

View File

@ -11,7 +11,6 @@ import 'package:spotube/services/mutations/mutations.dart';
import 'package:spotube/services/queries/queries.dart';
import 'package:spotube/utils/type_conversion_utils.dart';
import 'package:tuple/tuple.dart';
class HeartButton extends HookConsumerWidget {
final bool isLiked;
@ -60,8 +59,11 @@ class HeartButton extends HookConsumerWidget {
}
}
Tuple3<bool, Mutation<bool, dynamic, bool>, Query<User, dynamic>>
useTrackToggleLike(Track track, WidgetRef ref) {
({
bool isLiked,
Mutation<bool, dynamic, bool> toggleTrackLike,
Query<User?, dynamic> me,
}) useTrackToggleLike(Track track, WidgetRef ref) {
final me = useQueries.user.me(ref);
final savedTracks =
@ -101,7 +103,7 @@ Tuple3<bool, Mutation<bool, dynamic, bool>, Query<User, dynamic>>
},
);
return Tuple3(isLiked, toggleTrackLike, me);
return (isLiked: isLiked, toggleTrackLike: toggleTrackLike, me: me);
}
class TrackHeartButton extends HookConsumerWidget {
@ -116,18 +118,18 @@ class TrackHeartButton extends HookConsumerWidget {
final savedTracks =
useQueries.playlist.tracksOfQuery(ref, "user-liked-tracks");
final toggler = useTrackToggleLike(track, ref);
if (toggler.item3.isLoading || !toggler.item3.hasData) {
if (toggler.me.isLoading || !toggler.me.hasData) {
return const CircularProgressIndicator();
}
return HeartButton(
tooltip: toggler.item1
tooltip: toggler.isLiked
? context.l10n.remove_from_favorites
: context.l10n.save_as_favorite,
isLiked: toggler.item1,
isLiked: toggler.isLiked,
onPressed: savedTracks.hasData
? () {
toggler.item2.mutate(toggler.item1);
toggler.toggleTrackLike.mutate(toggler.isLiked);
}
: null,
);

View File

@ -316,16 +316,18 @@ class TrackTile extends HookConsumerWidget {
if (!playlist.containsTrack(track.value)) ...[
PopupMenuItem(
padding: EdgeInsets.zero,
onTap: () {
playback.addTrack(track.value);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
context.l10n
.added_track_to_queue(track.value.name!),
onTap: () async {
await playback.addTrack(track.value);
if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
context.l10n
.added_track_to_queue(track.value.name!),
),
),
),
);
);
}
},
child: ListTile(
leading: const Icon(SpotubeIcons.queueAdd),
@ -373,21 +375,21 @@ class TrackTile extends HookConsumerWidget {
title: Text(context.l10n.remove_from_queue),
),
),
if (toggler.item3.hasData)
if (toggler.me.hasData)
PopupMenuItem(
padding: EdgeInsets.zero,
onTap: () {
toggler.item2.mutate(toggler.item1);
toggler.toggleTrackLike.mutate(toggler.isLiked);
},
child: ListTile(
leading: toggler.item1
leading: toggler.isLiked
? const Icon(
SpotubeIcons.heartFilled,
color: Colors.pink,
)
: const Icon(SpotubeIcons.heart),
title: Text(
toggler.item1
toggler.isLiked
? context.l10n.remove_from_favorites
: context.l10n.save_as_favorite,
),

View File

@ -1,3 +1,4 @@
import 'package:collection/collection.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:spotify/spotify.dart';
import 'package:spotube/models/current_playlist.dart';
@ -56,21 +57,22 @@ class BlackListNotifier
}
bool contains(TrackSimple track) {
return filter([track]).isNotEmpty;
final containsTrack =
state.contains(BlacklistedElement.track(track.id!, track.name!));
final containsTrackArtists = track.artists?.any(
(artist) => state.contains(
BlacklistedElement.artist(artist.id!, artist.name!),
),
) ??
false;
return containsTrack || containsTrackArtists;
}
/// Filters the non blacklisted tracks from the given [tracks]
Iterable<TrackSimple> filter(Iterable<TrackSimple> tracks) {
return tracks.where(
(track) {
return !state
.contains(BlacklistedElement.track(track.id!, track.name!)) &&
!(track.artists ?? []).any(
(artist) => state.contains(
BlacklistedElement.artist(artist.id!, artist.name!),
),
);
},
).toList();
return tracks.whereNot(contains).toList();
}
CurrentPlaylist filterPlaylist(CurrentPlaylist playlist) {

View File

@ -21,7 +21,7 @@ import 'package:spotube/utils/type_conversion_utils.dart';
/// * [ ] Mixed Queue containing both [SpotubeTrack] and [LocalTrack]
/// * [ ] Modification of the Queue
/// * [x] Add track at the end
/// * [ ] Add track at the beginning
/// * [x] Add track at the beginning
/// * [x] Remove track
/// * [ ] Reorder track
/// * [ ] Caching and loading of cache of tracks
@ -277,7 +277,20 @@ class ProxyPlaylistNotifier extends StateNotifier<ProxyPlaylist>
await audioPlayer.moveTrack(oldIndex, newIndex);
}
Future<void> addTracksAtFirst(Iterable<Track> track) async {}
Future<void> addTracksAtFirst(Iterable<Track> tracks) async {
tracks = blacklist.filter(tracks).toList() as List<Track>;
final destIndex = state.active != null ? state.active! + 1 : 0;
final newTracks = state.tracks.toList()..insertAll(destIndex, tracks);
state = state.copyWith(tracks: newTracks.toSet());
tracks.forEachIndexed((index, track) async {
audioPlayer.addTrackAt(
makeAppropriateSource(track),
destIndex + index,
);
});
}
Future<void> populateSibling() async {}
Future<void> swapSibling(PipedSearchItem video) async {}

View File

@ -216,6 +216,16 @@ class SpotubeAudioPlayer extends AudioPlayerInterface
// }
}
Future<void> addTrackAt(String url, int index) async {
final urlType = _resolveUrlType(url);
// if (mkSupportedPlatform && urlType is mk.Media) {
await _mkPlayer.insert(index, urlType as mk.Media);
// } else {
// await (_justAudio!.audioSource as ja.ConcatenatingAudioSource)
// .insert(index, urlType as ja.AudioSource);
// }
}
Future<void> removeTrack(int index) async {
// if (mkSupportedPlatform) {
await _mkPlayer.remove(index);

View File

@ -243,6 +243,25 @@ class MkPlayerWithState extends Player {
}
}
FutureOr<void> insert(int index, Media media) {
if (_playlist == null ||
index < 0 ||
index > _playlist!.medias.length - 1) {
return null;
}
final newMedias = _playlist!.medias.toList()..insert(index, media);
playlist = _playlist!.copyWith(
medias: newMedias,
index: newMedias.indexOf(_playlist!.medias[_playlist!.index]),
);
if (shuffled && _tempMedias != null) {
_tempMedias!.insert(index, media);
}
}
/// Doesn't work when active media is the one to be removed
@override
FutureOr<void> remove(int index) async {

View File

@ -2,15 +2,17 @@ import 'package:fl_query/fl_query.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:spotify/spotify.dart';
import 'package:spotube/hooks/use_spotify_query.dart';
import 'package:spotube/provider/authentication_provider.dart';
import 'package:spotube/utils/type_conversion_utils.dart';
class UserQueries {
const UserQueries();
Query<User, dynamic> me(WidgetRef ref) {
Query<User?, dynamic> me(WidgetRef ref) {
return useSpotifyQuery<User, dynamic>(
"current-user",
(spotify) async {
final me = await spotify.me.get();
if (ref.read(AuthenticationNotifier.provider) == null) return null;
if (me.images == null || me.images?.isEmpty == true) {
me.images = [
Image()

View File

@ -1815,7 +1815,7 @@ packages:
source: hosted
version: "1.0.0"
tuple:
dependency: "direct main"
dependency: transitive
description:
name: tuple
sha256: "0ea99cd2f9352b2586583ab2ce6489d1f95a5f6de6fb9492faaf97ae2060f0aa"

View File

@ -88,7 +88,6 @@ dependencies:
spotify: ^0.11.0
system_theme: ^2.1.0
titlebar_buttons: ^1.0.0
tuple: ^2.0.1
url_launcher: ^6.1.7
uuid: ^3.0.7
version: ^3.0.2