mirror of
https://github.com/yattee/yattee.git
synced 2026-10-23 21:22:53 +00:00
Stretch the mini player's video preview to fill its frame
Wide videos showed letterbox bars in the tiny iOS mini player preview right after the dismiss morph, which lands the video filling the preview. The container that takes the shared player view now sets mpv's keepaspect, so the mini player fills its frame and every other surface keeps the aspect ratio.
This commit is contained in:
@@ -68,6 +68,9 @@ final class MPVBackend: PlayerBackend {
|
||||
// MARK: - Private Properties
|
||||
|
||||
private var mpvClient: MPVClient?
|
||||
#if os(iOS)
|
||||
private var videoFillsFrame = false
|
||||
#endif
|
||||
#if os(macOS)
|
||||
private var renderView: MPVOGLView?
|
||||
#elseif targetEnvironment(simulator) && (os(iOS) || os(tvOS))
|
||||
@@ -173,6 +176,14 @@ final class MPVBackend: PlayerBackend {
|
||||
_playerView?.pauseRendering()
|
||||
}
|
||||
|
||||
/// Stretch the video over the whole view (ignoring its aspect ratio)
|
||||
/// instead of letterboxing it.
|
||||
func setVideoFillsFrame(_ fills: Bool) {
|
||||
guard fills != videoFillsFrame else { return }
|
||||
videoFillsFrame = fills
|
||||
mpvClient?.setProperty("keepaspect", !fills)
|
||||
}
|
||||
|
||||
/// Resume video rendering
|
||||
func resumeRendering() {
|
||||
MPVLogging.log("MPVBackend.resumeRendering called")
|
||||
|
||||
@@ -18,10 +18,16 @@ struct MPVRenderViewRepresentable: UIViewRepresentable {
|
||||
/// Optional player state to update PiP availability
|
||||
var playerState: PlayerState?
|
||||
|
||||
/// Stretch the video to fill the view instead of letterboxing it (the mini
|
||||
/// player's tiny preview, where bars look like a glitch).
|
||||
var fillsFrame = false
|
||||
|
||||
func makeUIView(context: Context) -> UIView {
|
||||
// Create a container that will hold the actual player view
|
||||
let container = MPVContainerView()
|
||||
container.backgroundColor = .black
|
||||
container.backend = backend
|
||||
container.fillsFrame = fillsFrame
|
||||
|
||||
MPVLogging.log("MPVRenderViewRepresentable.makeUIView: creating container",
|
||||
details: "hasPlayerView:\(backend.playerView != nil)")
|
||||
@@ -64,6 +70,10 @@ private class MPVContainerView: UIView {
|
||||
private weak var currentPlayerView: UIView?
|
||||
private let containerID = UUID()
|
||||
|
||||
/// Applied to the backend whenever this container takes the player view
|
||||
weak var backend: MPVBackend?
|
||||
var fillsFrame = false
|
||||
|
||||
// Track all living containers to enable view transfer on deinit
|
||||
private static var livingContainers = NSHashTable<MPVContainerView>.weakObjects()
|
||||
|
||||
@@ -159,6 +169,9 @@ private class MPVContainerView: UIView {
|
||||
playerView.trailingAnchor.constraint(equalTo: trailingAnchor)
|
||||
])
|
||||
currentPlayerView = playerView
|
||||
#if os(iOS)
|
||||
backend?.setVideoFillsFrame(fillsFrame)
|
||||
#endif
|
||||
// Size it (and re-render its framebuffer) before anyone reacts to the move
|
||||
if !bounds.isEmpty {
|
||||
layoutIfNeeded()
|
||||
|
||||
@@ -344,8 +344,13 @@ struct MiniPlayerView: View {
|
||||
if let backend = playerService?.currentBackend as? MPVBackend,
|
||||
let playerState,
|
||||
shouldMountVideoView {
|
||||
#if os(iOS)
|
||||
MPVRenderViewRepresentable(backend: backend, playerState: playerState, fillsFrame: true)
|
||||
.allowsHitTesting(false)
|
||||
#else
|
||||
MPVRenderViewRepresentable(backend: backend, playerState: playerState)
|
||||
.allowsHitTesting(false)
|
||||
#endif
|
||||
}
|
||||
|
||||
// Thumbnail layer - on top so it can cover the black MPV view during PiP
|
||||
|
||||
Reference in New Issue
Block a user