mirror of
https://github.com/yattee/yattee.git
synced 2026-10-26 14:42:53 +00:00
Keep playlist affordances where an empty list took them
Three things live testing found, all of them where a playlist list or a playlist is empty. The picker said "This playlist has no videos" when there were no playlists to pick — copy about a playlist's contents standing in for copy about the list of them. Each section now says it has none, scoped to where it is: the device, or that account. An account whose fetch came back empty said nothing at all and left a bare gap. The browse view's Playlists tab fetched into its own state, so a playlist created through the picker — which goes through the shared cache — never appeared, and nothing refetched on coming back to the tab. It reads the cache now, and selecting the tab always refetches with the rows already there kept on screen. The cache is keyed by account, which is the discard on an account change the private copy needed a generation for. Removing the last video from a playlist took away the whole action row, so an owned server-side playlist could no longer be renamed or deleted from the app at all. The menu stays; only what needs videos to act on — play, download, save to library — goes.
This commit is contained in:
@@ -90,8 +90,12 @@ struct PlaylistSelectorSheet: View {
|
||||
}
|
||||
|
||||
// Existing playlists
|
||||
if !playlists.isEmpty {
|
||||
Section {
|
||||
Section {
|
||||
if playlists.isEmpty {
|
||||
emptyDestinationsRow(
|
||||
String(localized: "playlists.selector.empty.local")
|
||||
)
|
||||
} else {
|
||||
ForEach(playlists, id: \.id) { playlist in
|
||||
PlaylistSelectionRow(
|
||||
playlist: playlist,
|
||||
@@ -101,24 +105,12 @@ struct PlaylistSelectorSheet: View {
|
||||
addVideoToPlaylist(playlist)
|
||||
}
|
||||
}
|
||||
} header: {
|
||||
// Unlabelled while local playlists are the only
|
||||
// destinations there are.
|
||||
if !remoteDestinations.isEmpty {
|
||||
Text(String(localized: "playlist.section.local"))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Section {
|
||||
ContentUnavailableView {
|
||||
Label(
|
||||
String(localized: "playlist.empty.title"),
|
||||
systemImage: "music.note.list"
|
||||
)
|
||||
} description: {
|
||||
Text(String(localized: "playlist.empty.description"))
|
||||
}
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||
} header: {
|
||||
// Unlabelled while local playlists are the only
|
||||
// destinations there are.
|
||||
if !remoteDestinations.isEmpty {
|
||||
Text(String(localized: "playlist.section.local"))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -199,15 +191,24 @@ struct PlaylistSelectorSheet: View {
|
||||
}
|
||||
|
||||
if let remotePlaylists = appEnvironment?.remotePlaylistsCache.playlists(for: account.id) {
|
||||
ForEach(remotePlaylists) { playlist in
|
||||
RemotePlaylistSelectionRow(
|
||||
playlist: playlist,
|
||||
wasAdded: addedRemotePlaylist == RemoteSelection(
|
||||
accountID: account.id,
|
||||
playlistID: playlist.id.playlistID
|
||||
)
|
||||
) {
|
||||
Task { await addVideo(to: playlist, on: account) }
|
||||
if remotePlaylists.isEmpty {
|
||||
// The fetch landed and the account simply has none, which is
|
||||
// worth saying — the "New Playlist" row above it is the only
|
||||
// other thing in the section.
|
||||
emptyDestinationsRow(
|
||||
String(localized: "playlists.selector.empty.account")
|
||||
)
|
||||
} else {
|
||||
ForEach(remotePlaylists) { playlist in
|
||||
RemotePlaylistSelectionRow(
|
||||
playlist: playlist,
|
||||
wasAdded: addedRemotePlaylist == RemoteSelection(
|
||||
accountID: account.id,
|
||||
playlistID: playlist.id.playlistID
|
||||
)
|
||||
) {
|
||||
Task { await addVideo(to: playlist, on: account) }
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if loadingAccountIDs.contains(account.id) {
|
||||
@@ -222,6 +223,14 @@ struct PlaylistSelectorSheet: View {
|
||||
}
|
||||
}
|
||||
|
||||
/// Says that a section has no playlists to offer — not that some playlist is
|
||||
/// empty, which is a different sentence entirely.
|
||||
private func emptyDestinationsRow(_ text: String) -> some View {
|
||||
Text(text)
|
||||
.font(.subheadline)
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
|
||||
/// The account's name, and the host it lives on when the name does not
|
||||
/// already carry it (a login shows up as `user@host`).
|
||||
private func sectionTitle(for account: Account) -> String {
|
||||
|
||||
Reference in New Issue
Block a user