6f20a75f9b
Same fix shape as albums: drift's CachedPlaylistAdapter.toRef was returning coverUrl: '' because the cache table doesn't persist the server-derived URL. Set it to /api/playlists/<id>/cover in the adapter — handleGetPlaylistCover serves the cached collage from disk, so the URL is deterministic and the round-trip through drift no longer drops it. PlaylistCard + PlaylistsListScreen pass the existing queue_music icon as ServerImage's fallback, so when the server hasn't built a collage yet (system playlists with no tracks at build time), the endpoint 404s and the icon shows over the slate background instead of an empty box.
123 lines
4.0 KiB
Dart
123 lines
4.0 KiB
Dart
// Drift row → model adapters and reverse-write adapters for populating
|
|
// drift from REST responses (#357 plan C).
|
|
//
|
|
// The cache loses some server-derived fields:
|
|
// - ArtistRef.coverUrl (server computes from most-recent album)
|
|
// - AlbumRef.coverUrl (server-emitted derived path)
|
|
// - TrackRef.streamUrl (could be reconstructed but kept empty for clarity)
|
|
// UI already handles empty coverUrl/streamUrl gracefully. REST cold-cache
|
|
// fallback briefly shows the real values before drift takes over.
|
|
|
|
import 'package:drift/drift.dart' as drift;
|
|
|
|
import '../models/album.dart';
|
|
import '../models/artist.dart';
|
|
import '../models/playlist.dart';
|
|
import '../models/track.dart';
|
|
import 'db.dart';
|
|
|
|
extension CachedArtistAdapter on CachedArtist {
|
|
ArtistRef toRef() => ArtistRef(
|
|
id: id,
|
|
name: name,
|
|
sortName: sortName,
|
|
);
|
|
}
|
|
|
|
extension ArtistRefDriftWrite on ArtistRef {
|
|
CachedArtistsCompanion toDrift() => CachedArtistsCompanion.insert(
|
|
id: id,
|
|
name: name,
|
|
sortName: sortName.isNotEmpty ? sortName : name,
|
|
);
|
|
}
|
|
|
|
extension CachedAlbumAdapter on CachedAlbum {
|
|
/// `artistName` is supplied by the joined CachedArtists row at query time.
|
|
/// `coverUrl` is reconstructed deterministically from the album id —
|
|
/// the server emits the same shape (see internal/api/convert.go:69).
|
|
/// We don't need to persist it, so AlbumRef.coverUrl is non-empty
|
|
/// even when the row was populated from a sync that didn't carry the
|
|
/// derived URL.
|
|
AlbumRef toRef({String artistName = ''}) => AlbumRef(
|
|
id: id,
|
|
title: title,
|
|
sortTitle: sortTitle,
|
|
artistId: artistId,
|
|
artistName: artistName,
|
|
coverUrl: '/api/albums/$id/cover',
|
|
);
|
|
}
|
|
|
|
extension AlbumRefDriftWrite on AlbumRef {
|
|
CachedAlbumsCompanion toDrift() => CachedAlbumsCompanion.insert(
|
|
id: id,
|
|
artistId: artistId,
|
|
title: title,
|
|
sortTitle: sortTitle.isNotEmpty ? sortTitle : title,
|
|
);
|
|
}
|
|
|
|
extension CachedTrackAdapter on CachedTrack {
|
|
/// `artistName` and `albumTitle` come from joined rows.
|
|
TrackRef toRef({String artistName = '', String albumTitle = ''}) => TrackRef(
|
|
id: id,
|
|
title: title,
|
|
albumId: albumId,
|
|
albumTitle: albumTitle,
|
|
artistId: artistId,
|
|
artistName: artistName,
|
|
trackNumber: trackNumber,
|
|
discNumber: discNumber,
|
|
durationSec: durationMs ~/ 1000,
|
|
);
|
|
}
|
|
|
|
extension TrackRefDriftWrite on TrackRef {
|
|
CachedTracksCompanion toDrift() => CachedTracksCompanion.insert(
|
|
id: id,
|
|
albumId: albumId,
|
|
artistId: artistId,
|
|
title: title,
|
|
durationMs: drift.Value(durationSec * 1000),
|
|
trackNumber: drift.Value(trackNumber),
|
|
discNumber: drift.Value(discNumber),
|
|
);
|
|
}
|
|
|
|
extension CachedPlaylistAdapter on CachedPlaylist {
|
|
/// `ownerUsername` is server-derived; cache stores the userId only.
|
|
/// Pass empty unless a join supplies it.
|
|
/// `coverUrl` is reconstructed deterministically from the playlist
|
|
/// id — the server serves the cached collage at this path
|
|
/// (handleGetPlaylistCover). Mirrors the album-cover trick. When
|
|
/// the server hasn't built a collage yet (system playlists with no
|
|
/// tracks at build time), the endpoint 404s and PlaylistCard's
|
|
/// ServerImage falls back to its slate placeholder.
|
|
Playlist toRef({String ownerUsername = ''}) => Playlist(
|
|
id: id,
|
|
userId: userId,
|
|
name: name,
|
|
description: description,
|
|
isPublic: isPublic,
|
|
systemVariant: systemVariant,
|
|
trackCount: trackCount,
|
|
coverUrl: '/api/playlists/$id/cover',
|
|
ownerUsername: ownerUsername,
|
|
createdAt: '',
|
|
updatedAt: '',
|
|
);
|
|
}
|
|
|
|
extension PlaylistDriftWrite on Playlist {
|
|
CachedPlaylistsCompanion toDrift() => CachedPlaylistsCompanion.insert(
|
|
id: id,
|
|
userId: userId,
|
|
name: name,
|
|
description: drift.Value(description),
|
|
isPublic: drift.Value(isPublic),
|
|
trackCount: drift.Value(trackCount),
|
|
systemVariant: drift.Value(systemVariant),
|
|
);
|
|
}
|