Files
minstrel/flutter_client/lib/api/endpoints/playlists.dart
T
bvandeusen 5541171e94 feat(flutter): playlists list + detail screens
- 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.
2026-05-08 14:33:53 -04:00

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 {});
}
}