5541171e94
- models/playlist.dart (Playlist, PlaylistTrack, PlaylistDetail) - api/endpoints/playlists.dart (list with kind=user|system|all, get detail) - playlists/playlists_provider.dart (Riverpod family providers) - playlists/playlists_list_screen.dart (with system-variant pill) - playlists/playlist_detail_screen.dart (header + Play button + rows) - /playlists + /playlists/:id routes wired - Home AppBar: queue_music icon next to Search Tracks with track_id=null render greyed-out + struck-through (matches web's PlaylistTrackRow behavior). Tap a row plays from that position; top-level Play button plays the full playable subset from track 0.
29 lines
950 B
Dart
29 lines
950 B
Dart
import 'package:dio/dio.dart';
|
|
|
|
import '../../models/playlist.dart';
|
|
|
|
class PlaylistsApi {
|
|
PlaylistsApi(this._dio);
|
|
final Dio _dio;
|
|
|
|
/// GET /api/playlists?kind=user|system|all. The server's default kind
|
|
/// is "user" — passing "all" returns user playlists + system mixes.
|
|
/// "system" returns just for-you / discover. The mobile UI defaults
|
|
/// to "all" so users see their generated mixes alongside their own.
|
|
Future<List<Playlist>> list({String kind = 'all'}) async {
|
|
final r = await _dio.get<List<dynamic>>(
|
|
'/api/playlists',
|
|
queryParameters: {'kind': kind},
|
|
);
|
|
final raw = r.data ?? const [];
|
|
return raw
|
|
.map((e) => Playlist.fromJson((e as Map).cast<String, dynamic>()))
|
|
.toList(growable: false);
|
|
}
|
|
|
|
Future<PlaylistDetail> get(String id) async {
|
|
final r = await _dio.get<Map<String, dynamic>>('/api/playlists/$id');
|
|
return PlaylistDetail.fromJson(r.data ?? const {});
|
|
}
|
|
}
|