This commit is contained in:
Forrest 2026-08-04 16:08:51 -04:00
parent d558aba246
commit 3bd713d667
17 changed files with 1566 additions and 132 deletions

View file

@ -24,6 +24,12 @@ const String kTagMarker = 'timbre:tag';
/// Whether [p] is a Timbre tag (vs a user-facing playlist).
bool isTagPlaylist(Playlist p) => p.comment == kTagMarker;
/// Whether [p] belongs to the user [me] (vs a *shared* playlist owned by
/// someone else on the same server). An unknown owner — or unknown viewer —
/// counts as "mine" so the split never hides a playlist the user can edit.
bool isOwnedBy(Playlist p, String? me) =>
p.owner == null || me == null || p.owner == me;
/// Playlists snapshot: the summaries (from `getPlaylists`) plus any full details
/// that have been opened. Details are cached so an opened playlist keeps working
/// offline.
@ -279,6 +285,50 @@ class PlaylistsController extends StateNotifier<PlaylistsState> {
songs: d.songs,
);
/// Share (make server-wide public) or unshare a playlist. Optimistic like
/// [rename]; reverts on failure. Owner/public live on the summary only.
Future<void> setPublic(String id, bool value) async {
final client = _clientGetter();
if (client == null) return;
final prev = state;
state = state.copyWith(playlists: [
for (final p in state.playlists)
if (p.id == id) _withPublic(p, value) else p,
]);
try {
await client.setPlaylistPublic(id, value);
await _persist();
} catch (_) {
state = prev; // revert
}
}
/// Clone a (typically shared) playlist into a new one owned by the current
/// user — the client-only alternative to editing someone else's playlist.
/// Loads [source]'s tracks (server, falling back to cache), creates a fresh
/// playlist, and copies them in. Returns the new id, or null on failure.
Future<String?> saveCopy(Playlist source) async {
final client = _clientGetter();
if (client == null) return null;
final detail = await loadDetail(source.id);
final songs = detail?.songs ?? const <Song>[];
final newId = await create(source.name);
if (newId == null) return null;
if (songs.isNotEmpty) await addTracks(newId, songs);
return newId;
}
static Playlist _withPublic(Playlist p, bool value) => Playlist(
id: p.id,
name: p.name,
songCount: p.songCount,
duration: p.duration,
owner: p.owner,
public: value,
coverArt: p.coverArt,
comment: p.comment,
);
Future<void> rename(String id, String name) async {
final client = _clientGetter();
if (client == null) return;