Fix tvOS controls overlay buttons

This commit is contained in:
Arkadiusz Fal 2022-09-02 02:06:33 +02:00
parent f7dd88a6cb
commit eebca5ca59
4 changed files with 57 additions and 19 deletions

View File

@ -91,6 +91,13 @@ struct ControlsOverlay: View {
#if os(tvOS) #if os(tvOS)
.padding(.horizontal, 40) .padding(.horizontal, 40)
#endif #endif
#if os(tvOS)
Text("Press and hold remote button to open captions and quality menus")
.frame(maxWidth: 400)
.font(.caption)
.foregroundColor(.secondary)
#endif
} }
.frame(maxHeight: overlayHeight) .frame(maxHeight: overlayHeight)
#if os(tvOS) #if os(tvOS)
@ -105,7 +112,7 @@ struct ControlsOverlay: View {
private var overlayHeight: Double { private var overlayHeight: Double {
#if os(tvOS) #if os(tvOS)
contentSize.height + 50.0 contentSize.height + 80.0
#else #else
contentSize.height contentSize.height
#endif #endif
@ -255,9 +262,7 @@ struct ControlsOverlay: View {
.modifier(ControlBackgroundModifier()) .modifier(ControlBackgroundModifier())
.mask(RoundedRectangle(cornerRadius: 3)) .mask(RoundedRectangle(cornerRadius: 3))
#else #else
Button { ControlsOverlayButton(focusedField: $focusedField, field: .qualityProfile) {
presentingButtonHintAlert = true
} label: {
Text(player.qualityProfileSelection?.description ?? "Automatic") Text(player.qualityProfileSelection?.description ?? "Automatic")
.lineLimit(1) .lineLimit(1)
.frame(maxWidth: 320) .frame(maxWidth: 320)
@ -309,7 +314,7 @@ struct ControlsOverlay: View {
.modifier(ControlBackgroundModifier()) .modifier(ControlBackgroundModifier())
.mask(RoundedRectangle(cornerRadius: 3)) .mask(RoundedRectangle(cornerRadius: 3))
#else #else
StreamControl(presentingButtonHintAlert: $presentingButtonHintAlert) StreamControl(focusedField: $focusedField)
#endif #endif
} }
@ -339,9 +344,7 @@ struct ControlsOverlay: View {
.modifier(ControlBackgroundModifier()) .modifier(ControlBackgroundModifier())
.mask(RoundedRectangle(cornerRadius: 3)) .mask(RoundedRectangle(cornerRadius: 3))
#else #else
Button { ControlsOverlayButton(focusedField: $focusedField, field: .captions) {
presentingButtonHintAlert = true
} label: {
HStack(spacing: 8) { HStack(spacing: 8) {
Image(systemName: "text.bubble") Image(systemName: "text.bubble")
if let captions = captionsBinding.wrappedValue { if let captions = captionsBinding.wrappedValue {

View File

@ -1,14 +1,16 @@
import SwiftUI import SwiftUI
struct StreamControl: View { struct StreamControl: View {
@Binding var presentingButtonHintAlert: Bool #if os(tvOS)
var focusedField: FocusState<ControlsOverlay.Field?>.Binding?
init(focusedField: FocusState<ControlsOverlay.Field?>.Binding?) {
self.focusedField = focusedField
}
#endif
@EnvironmentObject<PlayerModel> private var player @EnvironmentObject<PlayerModel> private var player
init(presentingButtonHintAlert: Binding<Bool> = .constant(false)) {
_presentingButtonHintAlert = presentingButtonHintAlert
}
var body: some View { var body: some View {
Group { Group {
#if !os(tvOS) #if !os(tvOS)
@ -36,9 +38,7 @@ struct StreamControl: View {
.disabled(player.isLoadingAvailableStreams) .disabled(player.isLoadingAvailableStreams)
#endif #endif
#else #else
Button { ControlsOverlayButton(focusedField: focusedField!, field: .stream) {
presentingButtonHintAlert = true
} label: {
Text(player.streamSelection?.shortQuality ?? "loading") Text(player.streamSelection?.shortQuality ?? "loading")
.frame(maxWidth: 320) .frame(maxWidth: 320)
} }
@ -51,7 +51,6 @@ struct StreamControl: View {
} }
#endif #endif
} }
.transaction { t in t.animation = .none } .transaction { t in t.animation = .none }
.onChange(of: player.streamSelection) { selection in .onChange(of: player.streamSelection) { selection in
guard let selection = selection else { return } guard let selection = selection else { return }
@ -72,7 +71,11 @@ struct StreamControl: View {
struct StreamControl_Previews: PreviewProvider { struct StreamControl_Previews: PreviewProvider {
static var previews: some View { static var previews: some View {
StreamControl() #if os(tvOS)
.injectFixtureEnvironmentObjects() StreamControl(focusedField: .none)
.injectFixtureEnvironmentObjects()
#else
StreamControl()
#endif
} }
} }

View File

@ -748,6 +748,7 @@
37D6025928C17375009E8D98 /* PlaybackStatsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37D6025828C17375009E8D98 /* PlaybackStatsView.swift */; }; 37D6025928C17375009E8D98 /* PlaybackStatsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37D6025828C17375009E8D98 /* PlaybackStatsView.swift */; };
37D6025A28C17375009E8D98 /* PlaybackStatsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37D6025828C17375009E8D98 /* PlaybackStatsView.swift */; }; 37D6025A28C17375009E8D98 /* PlaybackStatsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37D6025828C17375009E8D98 /* PlaybackStatsView.swift */; };
37D6025B28C17375009E8D98 /* PlaybackStatsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37D6025828C17375009E8D98 /* PlaybackStatsView.swift */; }; 37D6025B28C17375009E8D98 /* PlaybackStatsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37D6025828C17375009E8D98 /* PlaybackStatsView.swift */; };
37D6025D28C17719009E8D98 /* ControlsOverlayButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37D6025C28C17719009E8D98 /* ControlsOverlayButton.swift */; };
37DD87C7271C9CFE0027CBF9 /* PlayerStreams.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37DD87C6271C9CFE0027CBF9 /* PlayerStreams.swift */; }; 37DD87C7271C9CFE0027CBF9 /* PlayerStreams.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37DD87C6271C9CFE0027CBF9 /* PlayerStreams.swift */; };
37DD87C8271C9CFE0027CBF9 /* PlayerStreams.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37DD87C6271C9CFE0027CBF9 /* PlayerStreams.swift */; }; 37DD87C8271C9CFE0027CBF9 /* PlayerStreams.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37DD87C6271C9CFE0027CBF9 /* PlayerStreams.swift */; };
37DD87C9271C9CFE0027CBF9 /* PlayerStreams.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37DD87C6271C9CFE0027CBF9 /* PlayerStreams.swift */; }; 37DD87C9271C9CFE0027CBF9 /* PlayerStreams.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37DD87C6271C9CFE0027CBF9 /* PlayerStreams.swift */; };
@ -1264,6 +1265,7 @@
37D4B1AE26729DEB00C925CA /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; 37D4B1AE26729DEB00C925CA /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
37D526DD2720AC4400ED2F5E /* VideosAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideosAPI.swift; sourceTree = "<group>"; }; 37D526DD2720AC4400ED2F5E /* VideosAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideosAPI.swift; sourceTree = "<group>"; };
37D6025828C17375009E8D98 /* PlaybackStatsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlaybackStatsView.swift; sourceTree = "<group>"; }; 37D6025828C17375009E8D98 /* PlaybackStatsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlaybackStatsView.swift; sourceTree = "<group>"; };
37D6025C28C17719009E8D98 /* ControlsOverlayButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ControlsOverlayButton.swift; sourceTree = "<group>"; };
37D9169A27388A81002B1BAA /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; }; 37D9169A27388A81002B1BAA /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
37DD87C6271C9CFE0027CBF9 /* PlayerStreams.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayerStreams.swift; sourceTree = "<group>"; }; 37DD87C6271C9CFE0027CBF9 /* PlayerStreams.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayerStreams.swift; sourceTree = "<group>"; };
37DD9DA22785BBC900539416 /* NoCommentsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoCommentsView.swift; sourceTree = "<group>"; }; 37DD9DA22785BBC900539416 /* NoCommentsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoCommentsView.swift; sourceTree = "<group>"; };
@ -2086,6 +2088,7 @@
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
37666BA927023AF000F869E5 /* AccountSelectionView.swift */, 37666BA927023AF000F869E5 /* AccountSelectionView.swift */,
37D6025C28C17719009E8D98 /* ControlsOverlayButton.swift */,
37FADFFF272ED58000330459 /* EditFavorites.swift */, 37FADFFF272ED58000330459 /* EditFavorites.swift */,
3730D89F2712E2B70020ED53 /* NowPlayingView.swift */, 3730D89F2712E2B70020ED53 /* NowPlayingView.swift */,
37BAB54B269B39FD00E75ED1 /* TVNavigationView.swift */, 37BAB54B269B39FD00E75ED1 /* TVNavigationView.swift */,
@ -3341,6 +3344,7 @@
3748187026A769D60084E870 /* DetailBadge.swift in Sources */, 3748187026A769D60084E870 /* DetailBadge.swift in Sources */,
3741A32C27E7EFFD00D266D1 /* PlayerControls.swift in Sources */, 3741A32C27E7EFFD00D266D1 /* PlayerControls.swift in Sources */,
371B7E632759706A00D21217 /* CommentsView.swift in Sources */, 371B7E632759706A00D21217 /* CommentsView.swift in Sources */,
37D6025D28C17719009E8D98 /* ControlsOverlayButton.swift in Sources */,
37D2E0D628B67EFC00F64D52 /* Delay.swift in Sources */, 37D2E0D628B67EFC00F64D52 /* Delay.swift in Sources */,
379F1421289ECE7F00DE48B5 /* QualitySettings.swift in Sources */, 379F1421289ECE7F00DE48B5 /* QualitySettings.swift in Sources */,
37A9965C26D6F8CA006E3224 /* HorizontalCells.swift in Sources */, 37A9965C26D6F8CA006E3224 /* HorizontalCells.swift in Sources */,

View File

@ -0,0 +1,28 @@
import SwiftUI
struct ControlsOverlayButton<LabelView: View>: View {
var focusedField: FocusState<ControlsOverlay.Field?>.Binding
var field: ControlsOverlay.Field
let label: LabelView
init(
focusedField: FocusState<ControlsOverlay.Field?>.Binding,
field: ControlsOverlay.Field,
@ViewBuilder label: @escaping () -> LabelView
) {
self.focusedField = focusedField
self.field = field
self.label = label()
}
var body: some View {
label
.padding()
.frame(width: 400)
.focusable()
.focused(focusedField, equals: field)
.background(focusedField.wrappedValue == field ? Color.white : Color.secondary)
.foregroundColor(focusedField.wrappedValue == field ? Color.black : Color.white)
.clipShape(RoundedRectangle(cornerRadius: 4))
}
}