Make unplayable tvOS media files focusable with unsupported alert

This commit is contained in:
Arkadiusz Fal
2026-04-17 05:59:00 +02:00
parent 4c8a3ee5ba
commit 39580d713b
3 changed files with 54 additions and 0 deletions

View File

@@ -4953,6 +4953,26 @@
} }
} }
}, },
"mediaBrowser.unsupportedFile.title" : {
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Unsupported file"
}
}
}
},
"mediaBrowser.unsupportedFile.message %@" : {
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "%@ cannot be played. This file type is not supported."
}
}
}
},
"mediaBrowser.sort.dateCreated" : { "mediaBrowser.sort.dateCreated" : {
"localizations" : { "localizations" : {
"en" : { "en" : {

View File

@@ -22,6 +22,9 @@ struct MediaBrowserView: View {
@State private var sortOrder: MediaBrowserSortOrder @State private var sortOrder: MediaBrowserSortOrder
@State private var sortAscending: Bool @State private var sortAscending: Bool
@State private var showViewOptions = false @State private var showViewOptions = false
#if os(tvOS)
@State private var unsupportedFile: MediaFile?
#endif
private var listStyle: VideoListStyle { private var listStyle: VideoListStyle {
appEnvironment?.settingsManager.listStyle ?? .inset appEnvironment?.settingsManager.listStyle ?? .inset
@@ -165,8 +168,14 @@ struct MediaBrowserView: View {
} else if file.isPlayable { } else if file.isPlayable {
playableFileRow(for: file) playableFileRow(for: file)
} else { } else {
#if os(tvOS)
MediaFileTVOSUnsupportedButton(onTap: { unsupportedFile = file }) {
MediaFileRow(file: file, sortOrder: sortOrder) MediaFileRow(file: file, sortOrder: sortOrder)
} }
#else
MediaFileRow(file: file, sortOrder: sortOrder)
#endif
}
} }
} }
} }
@@ -174,6 +183,20 @@ struct MediaBrowserView: View {
.padding(.top, 16) .padding(.top, 16)
} }
) )
#if os(tvOS)
.alert(
String(localized: "mediaBrowser.unsupportedFile.title"),
isPresented: Binding(
get: { unsupportedFile != nil },
set: { if !$0 { unsupportedFile = nil } }
),
presenting: unsupportedFile
) { _ in
Button(String(localized: "common.ok"), role: .cancel) { unsupportedFile = nil }
} message: { file in
Text(String(localized: "mediaBrowser.unsupportedFile.message \(file.name)"))
}
#endif
} }
@ViewBuilder @ViewBuilder

View File

@@ -35,6 +35,17 @@ struct MediaFileTVOSTapButton<Label: View>: View {
.buttonStyle(.plain) .buttonStyle(.plain)
} }
} }
/// tvOS-only: wraps an unplayable row in a Button so the focus engine can land on it.
struct MediaFileTVOSUnsupportedButton<Label: View>: View {
let onTap: () -> Void
@ViewBuilder let label: () -> Label
var body: some View {
Button(action: onTap) { label() }
.buttonStyle(.plain)
}
}
#else #else
/// iOS/macOS: per-region gesture used by MediaFileRow's icon and text areas. /// iOS/macOS: per-region gesture used by MediaFileRow's icon and text areas.
/// Only attaches a gesture when the action differs from `.playVideo`, letting /// Only attaches a gesture when the action differs from `.playVideo`, letting