diff --git a/Yattee/Localizable.xcstrings b/Yattee/Localizable.xcstrings index 4e803ee4..3959c34b 100644 --- a/Yattee/Localizable.xcstrings +++ b/Yattee/Localizable.xcstrings @@ -9391,6 +9391,17 @@ } } }, + "playlist.notFound.openPlaylists" : { + "comment" : "tvOS button on the playlist-not-found screen that opens the Playlists list", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Open Playlists" + } + } + } + }, "playlist.play" : { "comment" : "Play button in playlist toolbar menu", "localizations" : { diff --git a/Yattee/Views/Playlist/UnifiedPlaylistDetailView.swift b/Yattee/Views/Playlist/UnifiedPlaylistDetailView.swift index dd0fd7a2..9b25f4cb 100644 --- a/Yattee/Views/Playlist/UnifiedPlaylistDetailView.swift +++ b/Yattee/Views/Playlist/UnifiedPlaylistDetailView.swift @@ -252,12 +252,7 @@ struct UnifiedPlaylistDetailView: View { } else if let error = errorMessage { errorView(error) } else { - ContentUnavailableView( - String(localized: "playlist.notFound"), - systemImage: "list.bullet.rectangle", - description: Text(String(localized: "playlist.notFound.description")) - ) - .frame(maxWidth: .infinity, maxHeight: .infinity) + notFoundView } } #if !os(tvOS) @@ -819,11 +814,44 @@ struct UnifiedPlaylistDetailView: View { Label(String(localized: "playlist.empty"), systemImage: "music.note.list") } description: { Text(String(localized: "playlist.empty.description")) + } actions: { + #if os(tvOS) + // The left column has no buttons for an empty remote playlist this + // account does not own; without one the remote has nowhere to go. + if case .remote = source { + Button(String(localized: "common.refresh")) { + Task { await loadPlaylist() } + } + } + #endif } .frame(maxWidth: .infinity, maxHeight: .infinity) .padding(.top, 40) } + private var notFoundView: some View { + ContentUnavailableView { + Label(String(localized: "playlist.notFound"), systemImage: "list.bullet.rectangle") + } description: { + Text(String(localized: "playlist.notFound.description")) + } actions: { + #if os(tvOS) + // Nothing else on this screen is focusable, and as a sidebar + // playlist it is a tab root that Menu cannot pop. + if case .remote = source { + Button(String(localized: "common.retry")) { + Task { await loadPlaylist() } + } + } else { + Button(String(localized: "playlist.notFound.openPlaylists")) { + appEnvironment?.navigationCoordinator.router.select(.playlistsList) + } + } + #endif + } + .frame(maxWidth: .infinity, maxHeight: .infinity) + } + private var videoList: some View { #if os(tvOS) let indexColumnWidth: CGFloat = 60