tvOS layout improvements

This commit is contained in:
Arkadiusz Fal 2022-08-14 18:59:04 +02:00
parent 8d7359f012
commit 27d140af01
5 changed files with 52 additions and 21 deletions

View File

@ -40,7 +40,12 @@ final class PlayerModel: ObservableObject {
var mpvPlayerView = MPVPlayerView() var mpvPlayerView = MPVPlayerView()
@Published var presentingPlayer = true { didSet { handlePresentationChange() } } #if os(iOS)
static let presentingPlayerDefault = true
#else
static let presentingPlayerDefault = false
#endif
@Published var presentingPlayer = presentingPlayerDefault { didSet { handlePresentationChange() } }
@Published var activeBackend = PlayerBackendType.mpv @Published var activeBackend = PlayerBackendType.mpv
var avPlayerBackend: AVPlayerBackend! var avPlayerBackend: AVPlayerBackend!
@ -63,7 +68,9 @@ final class PlayerModel: ObservableObject {
} }
@Published var playerSize: CGSize = .zero { didSet { @Published var playerSize: CGSize = .zero { didSet {
#if !os(tvOS)
backend.setSize(playerSize.width, playerSize.height) backend.setSize(playerSize.width, playerSize.height)
#endif
}} }}
@Published var aspectRatio = VideoPlayerView.defaultAspectRatio @Published var aspectRatio = VideoPlayerView.defaultAspectRatio
@Published var stream: Stream? @Published var stream: Stream?
@ -880,13 +887,14 @@ final class PlayerModel: ObservableObject {
mpvBackend.setVideoToAuto() mpvBackend.setVideoToAuto()
} }
func updateAspectRatio() { func updateAspectRatio() {
#if !os(tvOS)
guard aspectRatio != backend.aspectRatio else { return } guard aspectRatio != backend.aspectRatio else { return }
DispatchQueue.main.async { [weak self] in DispatchQueue.main.async { [weak self] in
guard let self = self else { return } guard let self = self else { return }
self.aspectRatio = self.backend.aspectRatio self.aspectRatio = self.backend.aspectRatio
} }
#endif
} }
} }

View File

@ -10,8 +10,6 @@ struct TVControls: UIViewRepresentable {
@State private var controlsArea = UIView() @State private var controlsArea = UIView()
func makeUIView(context: Context) -> UIView { func makeUIView(context: Context) -> UIView {
let tapGesture = UITapGestureRecognizer(target: context.coordinator, action: #selector(Coordinator.handleTap(sender:)))
let leftSwipe = UISwipeGestureRecognizer(target: context.coordinator, action: #selector(Coordinator.handleSwipe(sender:))) let leftSwipe = UISwipeGestureRecognizer(target: context.coordinator, action: #selector(Coordinator.handleSwipe(sender:)))
leftSwipe.direction = .left leftSwipe.direction = .left
@ -24,7 +22,6 @@ struct TVControls: UIViewRepresentable {
let downSwipe = UISwipeGestureRecognizer(target: context.coordinator, action: #selector(Coordinator.handleSwipe(sender:))) let downSwipe = UISwipeGestureRecognizer(target: context.coordinator, action: #selector(Coordinator.handleSwipe(sender:)))
downSwipe.direction = .down downSwipe.direction = .down
controlsArea.addGestureRecognizer(tapGesture)
controlsArea.addGestureRecognizer(leftSwipe) controlsArea.addGestureRecognizer(leftSwipe)
controlsArea.addGestureRecognizer(rightSwipe) controlsArea.addGestureRecognizer(rightSwipe)
controlsArea.addGestureRecognizer(upSwipe) controlsArea.addGestureRecognizer(upSwipe)
@ -62,16 +59,9 @@ struct TVControls: UIViewRepresentable {
fatalError("init(coder:) has not been implemented") fatalError("init(coder:) has not been implemented")
} }
@objc func handleTap(sender: UITapGestureRecognizer) {
let location = sender.location(in: view)
model.reporter.send("tap \(location)")
print("tap \(location)")
}
@objc func handleSwipe(sender: UISwipeGestureRecognizer) { @objc func handleSwipe(sender: UISwipeGestureRecognizer) {
let location = sender.location(in: view) let location = sender.location(in: view)
model.reporter.send("swipe \(location)") model.reporter.send("swipe \(location)")
print("swipe \(location)")
} }
} }
} }

View File

@ -33,7 +33,6 @@ struct PlayerBackendView: View {
.onAppear { player.playerSize = proxy.size } .onAppear { player.playerSize = proxy.size }
.onChange(of: proxy.size) { _ in player.playerSize = proxy.size } .onChange(of: proxy.size) { _ in player.playerSize = proxy.size }
.onChange(of: player.controls.presentingOverlays) { _ in player.playerSize = proxy.size } .onChange(of: player.controls.presentingOverlays) { _ in player.playerSize = proxy.size }
.onChange(of: player.aspectRatio) { _ in player.playerSize = proxy.size }
}) })
#if os(iOS) #if os(iOS)
.padding(.top, player.playingFullScreen && verticalSizeClass == .regular ? 20 : 0) .padding(.top, player.playingFullScreen && verticalSizeClass == .regular ? 20 : 0)
@ -46,6 +45,8 @@ struct PlayerBackendView: View {
.padding(.top, controlsTopPadding) .padding(.top, controlsTopPadding)
.padding(.bottom, controlsBottomPadding) .padding(.bottom, controlsBottomPadding)
#endif #endif
#else
hiddenControlsButton
#endif #endif
} }
#if os(iOS) #if os(iOS)
@ -82,6 +83,22 @@ struct PlayerBackendView: View {
} }
} }
#endif #endif
#if os(tvOS)
private var hiddenControlsButton: some View {
VStack {
Button {
player.controls.show()
} label: {
EmptyView()
}
.offset(y: -100)
.buttonStyle(.plain)
.background(Color.clear)
.foregroundColor(.clear)
}
}
#endif
} }
struct PlayerBackendView_Previews: PreviewProvider { struct PlayerBackendView_Previews: PreviewProvider {

View File

@ -238,6 +238,8 @@ struct YatteeApp: App {
player.updateRemoteCommandCenter() player.updateRemoteCommandCenter()
#endif #endif
if player.presentingPlayer {
player.presentingPlayer = false player.presentingPlayer = false
} }
} }
}

View File

@ -10,6 +10,8 @@ struct TVNavigationView: View {
@Default(.visibleSections) private var visibleSections @Default(.visibleSections) private var visibleSections
@State private var playerInitialized = false
var body: some View { var body: some View {
NavigationView { NavigationView {
TabView(selection: navigation.tabSelectionBinding) { TabView(selection: navigation.tabSelectionBinding) {
@ -52,11 +54,11 @@ struct TVNavigationView: View {
.tag(TabSelection.search) .tag(TabSelection.search)
SettingsView() SettingsView()
.navigationBarHidden(true)
.tabItem { Image(systemName: "gear") } .tabItem { Image(systemName: "gear") }
.tag(TabSelection.settings) .tag(TabSelection.settings)
} }
} }
.background(videoPlayerInitialize)
.fullScreenCover(isPresented: $navigation.presentingAddToPlaylist) { .fullScreenCover(isPresented: $navigation.presentingAddToPlaylist) {
if let video = navigation.videoToAddToPlaylist { if let video = navigation.videoToAddToPlaylist {
AddToPlaylistView(video: video) AddToPlaylistView(video: video)
@ -76,6 +78,18 @@ struct TVNavigationView: View {
} }
} }
} }
@ViewBuilder var videoPlayerInitialize: some View {
if !playerInitialized {
VideoPlayerView()
.scaleEffect(0.00001)
.onAppear {
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
playerInitialized = true
}
}
}
}
} }
struct TVNavigationView_Previews: PreviewProvider { struct TVNavigationView_Previews: PreviewProvider {