Skip to content

Commit

Permalink
fix: re-enable add to queue and play next support, favorite button qu…
Browse files Browse the repository at this point in the history
…ery exceptions
  • Loading branch information
KRTirtho committed May 27, 2023
1 parent bf59570 commit e529c79
Show file tree
Hide file tree
Showing 9 changed files with 87 additions and 38 deletions.
18 changes: 10 additions & 8 deletions lib/components/shared/heart_button.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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 =
Expand Down Expand Up @@ -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 {
Expand All @@ -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,
);
Expand Down
28 changes: 15 additions & 13 deletions lib/components/shared/track_table/track_tile.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down Expand Up @@ -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,
),
Expand Down
26 changes: 14 additions & 12 deletions lib/provider/blacklist_provider.dart
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -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) {
Expand Down
17 changes: 15 additions & 2 deletions lib/provider/proxy_playlist/proxy_playlist_provider.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 {}

Expand Down
10 changes: 10 additions & 0 deletions lib/services/audio_player/audio_player_impl.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
19 changes: 19 additions & 0 deletions lib/services/audio_player/mk_state_player.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
4 changes: 3 additions & 1 deletion lib/services/queries/user.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
2 changes: 1 addition & 1 deletion pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1815,7 +1815,7 @@ packages:
source: hosted
version: "1.0.0"
tuple:
dependency: "direct main"
dependency: transitive
description:
name: tuple
sha256: "0ea99cd2f9352b2586583ab2ce6489d1f95a5f6de6fb9492faaf97ae2060f0aa"
Expand Down
1 change: 0 additions & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit e529c79

Please sign in to comment.