fix(playback): alternative track sources switch not working

This commit is contained in:
Kingkor Roy Tirtho 2025-09-08 15:31:29 +06:00
parent 4a07945214
commit 58dc80aa09
5 changed files with 49 additions and 26 deletions

View File

@ -18,6 +18,7 @@ import 'package:spotube/hooks/utils/use_debounce.dart';
import 'package:spotube/models/database/database.dart';
import 'package:spotube/models/metadata/metadata.dart';
import 'package:spotube/models/playback/track_sources.dart';
import 'package:spotube/provider/audio_player/audio_player.dart';
import 'package:spotube/provider/audio_player/querying_track_info.dart';
import 'package:spotube/provider/server/active_track_sources.dart';
import 'package:spotube/provider/user_preferences/user_preferences_provider.dart';
@ -95,7 +96,7 @@ class SiblingTracksSheet extends HookConsumerWidget {
final controller = useScrollController();
final searchRequest = useMemoized(() async {
if (searchTerm.trim().isEmpty) {
if (searchTerm.trim().isEmpty || activeTrackSource == null) {
return <TrackSourceInfo>[];
}
if (preferences.audioSource == AudioSource.jiosaavn) {
@ -107,7 +108,7 @@ class SiblingTracksSheet extends HookConsumerWidget {
return siblingType.info;
}));
final activeSourceInfo = activeTrackSource?.info as TrackSourceInfo;
final activeSourceInfo = activeTrackSource.info;
return results
..removeWhere((element) => element.id == activeSourceInfo.id)
@ -122,18 +123,18 @@ class SiblingTracksSheet extends HookConsumerWidget {
resultsYt
.map(YoutubeVideoInfo.fromVideo)
.mapIndexed((i, video) async {
final siblingType =
await YoutubeSourcedTrack.toSiblingType(i, video, ref);
return siblingType.info;
}),
if (!context.mounted) return null;
final siblingType =
await YoutubeSourcedTrack.toSiblingType(i, video, ref);
return siblingType.info;
})
.whereType<Future<TrackSourceInfo>>()
.toList(),
);
final activeSourceInfo = activeTrackSource?.info as TrackSourceInfo;
final activeSourceInfo = activeTrackSource.info;
return searchResults
..removeWhere((element) => element.id == activeSourceInfo.id)
..insert(
0,
activeSourceInfo,
);
..insert(0, activeSourceInfo);
}
}, [
searchTerm,
@ -165,8 +166,8 @@ class SiblingTracksSheet extends HookConsumerWidget {
}, [activeTrack, previousActiveTrack]);
final itemBuilder = useCallback(
(TrackSourceInfo sourceInfo) {
final icon = sourceInfoToIconMap[sourceInfo.runtimeType];
(TrackSourceInfo sourceInfo, AudioSource source) {
final icon = sourceInfoToIconMap[source];
return ButtonTile(
style: ButtonVariance.ghost,
padding: const EdgeInsets.symmetric(horizontal: 8),
@ -197,14 +198,18 @@ class SiblingTracksSheet extends HookConsumerWidget {
enabled: !isFetchingActiveTrack,
selected: !isFetchingActiveTrack &&
sourceInfo.id == activeTrackSource?.info.id,
onPressed: () {
onPressed: () async {
if (!isFetchingActiveTrack &&
sourceInfo.id != activeTrackSource?.info.id) {
activeTrackNotifier?.swapWithSibling(sourceInfo);
if (MediaQuery.sizeOf(context).mdAndUp) {
closeOverlay(context);
} else {
closeDrawer(context);
await activeTrackNotifier?.swapWithSibling(sourceInfo);
await ref.read(audioPlayerProvider.notifier).swapActiveSource();
if (context.mounted) {
if (MediaQuery.sizeOf(context).mdAndUp) {
closeOverlay(context);
} else {
closeDrawer(context);
}
}
}
},
@ -301,8 +306,8 @@ class SiblingTracksSheet extends HookConsumerWidget {
controller: controller,
itemCount: siblings.length,
separatorBuilder: (context, index) => const Gap(8),
itemBuilder: (context, index) =>
itemBuilder(siblings[index]),
itemBuilder: (context, index) => itemBuilder(
siblings[index], activeTrackSource!.source),
),
true => FutureBuilder(
future: searchRequest,
@ -321,8 +326,10 @@ class SiblingTracksSheet extends HookConsumerWidget {
controller: controller,
itemCount: snapshot.data!.length,
separatorBuilder: (context, index) => const Gap(8),
itemBuilder: (context, index) =>
itemBuilder(snapshot.data![index]),
itemBuilder: (context, index) => itemBuilder(
snapshot.data![index],
preferences.audioSource,
),
);
},
),

View File

@ -421,6 +421,20 @@ class AudioPlayerNotifier extends Notifier<AudioPlayerState> {
);
}
Future<void> swapActiveSource() async {
if (state.tracks.isEmpty || state.activeTrack is! SpotubeFullTrackObject) {
return;
}
final currentIndex = state.currentIndex;
final currentTrack = state.activeTrack as SpotubeFullTrackObject;
final swappedMedia = SpotubeMedia(currentTrack);
await audioPlayer.addTrackAt(swappedMedia, currentIndex + 1);
await audioPlayer.skipToNext();
await audioPlayer.removeTrack(currentIndex);
}
Future<void> jumpToTrack(SpotubeTrackObject track) async {
final index =
state.tracks.toList().indexWhere((element) => element.id == track.id);

View File

@ -216,7 +216,7 @@ class JioSaavnSourcedTrack extends SourcedTrack {
ref: ref,
siblings: newSiblings,
sources: source!,
info: info,
info: newSourceInfo,
query: query,
source: AudioSource.jiosaavn,
);

View File

@ -269,7 +269,7 @@ class PipedSourcedTrack extends SourcedTrack {
ref: ref,
siblings: newSiblings,
sources: toSources(manifest),
info: info,
info: newSourceInfo,
query: query,
source: source,
);

View File

@ -120,6 +120,7 @@ class YoutubeSourcedTrack extends SourcedTrack {
dynamic ref,
) async {
assert(ref is WidgetRef || ref is Ref, "Invalid ref type");
List<TrackSource>? sourceMap;
if (index == 0) {
final manifest =
@ -338,6 +339,7 @@ class YoutubeSourcedTrack extends SourcedTrack {
final newSourceInfo = isStepSibling
? sibling
: siblings.firstWhere((s) => s.id == sibling.id);
final newSiblings = siblings.where((s) => s.id != sibling.id).toList()
..insert(0, info);
@ -364,7 +366,7 @@ class YoutubeSourcedTrack extends SourcedTrack {
source: source,
siblings: newSiblings,
sources: toTrackSources(manifest),
info: info,
info: newSourceInfo,
query: query,
);
}