mirror of
https://github.com/KRTirtho/spotube.git
synced 2025-09-13 16:05:18 +00:00
fix: re-enable add to queue and play next support, favorite button query exceptions
This commit is contained in:
parent
bf59570251
commit
e529c79c4f
@ -11,7 +11,6 @@ import 'package:spotube/services/mutations/mutations.dart';
|
|||||||
import 'package:spotube/services/queries/queries.dart';
|
import 'package:spotube/services/queries/queries.dart';
|
||||||
|
|
||||||
import 'package:spotube/utils/type_conversion_utils.dart';
|
import 'package:spotube/utils/type_conversion_utils.dart';
|
||||||
import 'package:tuple/tuple.dart';
|
|
||||||
|
|
||||||
class HeartButton extends HookConsumerWidget {
|
class HeartButton extends HookConsumerWidget {
|
||||||
final bool isLiked;
|
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 me = useQueries.user.me(ref);
|
||||||
|
|
||||||
final savedTracks =
|
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 {
|
class TrackHeartButton extends HookConsumerWidget {
|
||||||
@ -116,18 +118,18 @@ class TrackHeartButton extends HookConsumerWidget {
|
|||||||
final savedTracks =
|
final savedTracks =
|
||||||
useQueries.playlist.tracksOfQuery(ref, "user-liked-tracks");
|
useQueries.playlist.tracksOfQuery(ref, "user-liked-tracks");
|
||||||
final toggler = useTrackToggleLike(track, ref);
|
final toggler = useTrackToggleLike(track, ref);
|
||||||
if (toggler.item3.isLoading || !toggler.item3.hasData) {
|
if (toggler.me.isLoading || !toggler.me.hasData) {
|
||||||
return const CircularProgressIndicator();
|
return const CircularProgressIndicator();
|
||||||
}
|
}
|
||||||
|
|
||||||
return HeartButton(
|
return HeartButton(
|
||||||
tooltip: toggler.item1
|
tooltip: toggler.isLiked
|
||||||
? context.l10n.remove_from_favorites
|
? context.l10n.remove_from_favorites
|
||||||
: context.l10n.save_as_favorite,
|
: context.l10n.save_as_favorite,
|
||||||
isLiked: toggler.item1,
|
isLiked: toggler.isLiked,
|
||||||
onPressed: savedTracks.hasData
|
onPressed: savedTracks.hasData
|
||||||
? () {
|
? () {
|
||||||
toggler.item2.mutate(toggler.item1);
|
toggler.toggleTrackLike.mutate(toggler.isLiked);
|
||||||
}
|
}
|
||||||
: null,
|
: null,
|
||||||
);
|
);
|
||||||
|
@ -316,16 +316,18 @@ class TrackTile extends HookConsumerWidget {
|
|||||||
if (!playlist.containsTrack(track.value)) ...[
|
if (!playlist.containsTrack(track.value)) ...[
|
||||||
PopupMenuItem(
|
PopupMenuItem(
|
||||||
padding: EdgeInsets.zero,
|
padding: EdgeInsets.zero,
|
||||||
onTap: () {
|
onTap: () async {
|
||||||
playback.addTrack(track.value);
|
await playback.addTrack(track.value);
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
if (context.mounted) {
|
||||||
SnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
content: Text(
|
SnackBar(
|
||||||
context.l10n
|
content: Text(
|
||||||
.added_track_to_queue(track.value.name!),
|
context.l10n
|
||||||
|
.added_track_to_queue(track.value.name!),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
);
|
||||||
);
|
}
|
||||||
},
|
},
|
||||||
child: ListTile(
|
child: ListTile(
|
||||||
leading: const Icon(SpotubeIcons.queueAdd),
|
leading: const Icon(SpotubeIcons.queueAdd),
|
||||||
@ -373,21 +375,21 @@ class TrackTile extends HookConsumerWidget {
|
|||||||
title: Text(context.l10n.remove_from_queue),
|
title: Text(context.l10n.remove_from_queue),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (toggler.item3.hasData)
|
if (toggler.me.hasData)
|
||||||
PopupMenuItem(
|
PopupMenuItem(
|
||||||
padding: EdgeInsets.zero,
|
padding: EdgeInsets.zero,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
toggler.item2.mutate(toggler.item1);
|
toggler.toggleTrackLike.mutate(toggler.isLiked);
|
||||||
},
|
},
|
||||||
child: ListTile(
|
child: ListTile(
|
||||||
leading: toggler.item1
|
leading: toggler.isLiked
|
||||||
? const Icon(
|
? const Icon(
|
||||||
SpotubeIcons.heartFilled,
|
SpotubeIcons.heartFilled,
|
||||||
color: Colors.pink,
|
color: Colors.pink,
|
||||||
)
|
)
|
||||||
: const Icon(SpotubeIcons.heart),
|
: const Icon(SpotubeIcons.heart),
|
||||||
title: Text(
|
title: Text(
|
||||||
toggler.item1
|
toggler.isLiked
|
||||||
? context.l10n.remove_from_favorites
|
? context.l10n.remove_from_favorites
|
||||||
: context.l10n.save_as_favorite,
|
: context.l10n.save_as_favorite,
|
||||||
),
|
),
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import 'package:collection/collection.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:spotify/spotify.dart';
|
import 'package:spotify/spotify.dart';
|
||||||
import 'package:spotube/models/current_playlist.dart';
|
import 'package:spotube/models/current_playlist.dart';
|
||||||
@ -56,21 +57,22 @@ class BlackListNotifier
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool contains(TrackSimple track) {
|
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) {
|
Iterable<TrackSimple> filter(Iterable<TrackSimple> tracks) {
|
||||||
return tracks.where(
|
return tracks.whereNot(contains).toList();
|
||||||
(track) {
|
|
||||||
return !state
|
|
||||||
.contains(BlacklistedElement.track(track.id!, track.name!)) &&
|
|
||||||
!(track.artists ?? []).any(
|
|
||||||
(artist) => state.contains(
|
|
||||||
BlacklistedElement.artist(artist.id!, artist.name!),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
).toList();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CurrentPlaylist filterPlaylist(CurrentPlaylist playlist) {
|
CurrentPlaylist filterPlaylist(CurrentPlaylist playlist) {
|
||||||
|
@ -21,7 +21,7 @@ import 'package:spotube/utils/type_conversion_utils.dart';
|
|||||||
/// * [ ] Mixed Queue containing both [SpotubeTrack] and [LocalTrack]
|
/// * [ ] Mixed Queue containing both [SpotubeTrack] and [LocalTrack]
|
||||||
/// * [ ] Modification of the Queue
|
/// * [ ] Modification of the Queue
|
||||||
/// * [x] Add track at the end
|
/// * [x] Add track at the end
|
||||||
/// * [ ] Add track at the beginning
|
/// * [x] Add track at the beginning
|
||||||
/// * [x] Remove track
|
/// * [x] Remove track
|
||||||
/// * [ ] Reorder track
|
/// * [ ] Reorder track
|
||||||
/// * [ ] Caching and loading of cache of tracks
|
/// * [ ] Caching and loading of cache of tracks
|
||||||
@ -277,7 +277,20 @@ class ProxyPlaylistNotifier extends StateNotifier<ProxyPlaylist>
|
|||||||
await audioPlayer.moveTrack(oldIndex, newIndex);
|
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> populateSibling() async {}
|
||||||
Future<void> swapSibling(PipedSearchItem video) async {}
|
Future<void> swapSibling(PipedSearchItem video) async {}
|
||||||
|
|
||||||
|
@ -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 {
|
Future<void> removeTrack(int index) async {
|
||||||
// if (mkSupportedPlatform) {
|
// if (mkSupportedPlatform) {
|
||||||
await _mkPlayer.remove(index);
|
await _mkPlayer.remove(index);
|
||||||
|
@ -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
|
/// Doesn't work when active media is the one to be removed
|
||||||
@override
|
@override
|
||||||
FutureOr<void> remove(int index) async {
|
FutureOr<void> remove(int index) async {
|
||||||
|
@ -2,15 +2,17 @@ import 'package:fl_query/fl_query.dart';
|
|||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:spotify/spotify.dart';
|
import 'package:spotify/spotify.dart';
|
||||||
import 'package:spotube/hooks/use_spotify_query.dart';
|
import 'package:spotube/hooks/use_spotify_query.dart';
|
||||||
|
import 'package:spotube/provider/authentication_provider.dart';
|
||||||
import 'package:spotube/utils/type_conversion_utils.dart';
|
import 'package:spotube/utils/type_conversion_utils.dart';
|
||||||
|
|
||||||
class UserQueries {
|
class UserQueries {
|
||||||
const UserQueries();
|
const UserQueries();
|
||||||
Query<User, dynamic> me(WidgetRef ref) {
|
Query<User?, dynamic> me(WidgetRef ref) {
|
||||||
return useSpotifyQuery<User, dynamic>(
|
return useSpotifyQuery<User, dynamic>(
|
||||||
"current-user",
|
"current-user",
|
||||||
(spotify) async {
|
(spotify) async {
|
||||||
final me = await spotify.me.get();
|
final me = await spotify.me.get();
|
||||||
|
if (ref.read(AuthenticationNotifier.provider) == null) return null;
|
||||||
if (me.images == null || me.images?.isEmpty == true) {
|
if (me.images == null || me.images?.isEmpty == true) {
|
||||||
me.images = [
|
me.images = [
|
||||||
Image()
|
Image()
|
||||||
|
@ -1815,7 +1815,7 @@ packages:
|
|||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.0"
|
version: "1.0.0"
|
||||||
tuple:
|
tuple:
|
||||||
dependency: "direct main"
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: tuple
|
name: tuple
|
||||||
sha256: "0ea99cd2f9352b2586583ab2ce6489d1f95a5f6de6fb9492faaf97ae2060f0aa"
|
sha256: "0ea99cd2f9352b2586583ab2ce6489d1f95a5f6de6fb9492faaf97ae2060f0aa"
|
||||||
|
@ -88,7 +88,6 @@ dependencies:
|
|||||||
spotify: ^0.11.0
|
spotify: ^0.11.0
|
||||||
system_theme: ^2.1.0
|
system_theme: ^2.1.0
|
||||||
titlebar_buttons: ^1.0.0
|
titlebar_buttons: ^1.0.0
|
||||||
tuple: ^2.0.1
|
|
||||||
url_launcher: ^6.1.7
|
url_launcher: ^6.1.7
|
||||||
uuid: ^3.0.7
|
uuid: ^3.0.7
|
||||||
version: ^3.0.2
|
version: ^3.0.2
|
||||||
|
Loading…
Reference in New Issue
Block a user