mastodon-ios/Mastodon/Scene/Share/View/Container/PlayerContainerView.swift

163 lines
7.5 KiB
Swift
Raw Normal View History

2021-03-10 07:36:28 +01:00
//
2021-03-11 12:06:15 +01:00
// PlayerContainerView.swift
2021-03-10 07:36:28 +01:00
// Mastodon
//
// Created by xiaojian sun on 2021/3/10.
//
import os.log
2021-03-10 07:36:28 +01:00
import AVKit
import UIKit
2021-03-11 12:06:15 +01:00
protocol PlayerContainerViewDelegate: class {
func playerContainerView(_ playerContainerView: PlayerContainerView, contentWarningOverlayViewDidPressed contentWarningOverlayView: ContentWarningOverlayView)
}
final class PlayerContainerView: UIView {
2021-03-10 07:36:28 +01:00
static let cornerRadius: CGFloat = 8
private let container = UIView()
private let touchBlockingView = TouchBlockingView()
private var containerHeightLayoutConstraint: NSLayoutConstraint!
2021-03-11 12:06:15 +01:00
let contentWarningOverlayView: ContentWarningOverlayView = {
let contentWarningOverlayView = ContentWarningOverlayView()
contentWarningOverlayView.update(cornerRadius: PlayerContainerView.cornerRadius)
2021-03-11 12:06:15 +01:00
return contentWarningOverlayView
2021-03-11 08:10:41 +01:00
}()
2021-03-10 07:36:28 +01:00
let playerViewController = AVPlayerViewController()
let mediaTypeIndicotorView = MediaTypeIndicotorView()
let mediaTypeIndicotorViewInContentWarningOverlay = MediaTypeIndicotorView()
2021-03-11 12:06:15 +01:00
weak var delegate: PlayerContainerViewDelegate?
2021-03-10 07:36:28 +01:00
override init(frame: CGRect) {
super.init(frame: frame)
_init()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
_init()
}
}
2021-03-11 12:06:15 +01:00
extension PlayerContainerView {
2021-03-10 07:36:28 +01:00
private func _init() {
container.translatesAutoresizingMaskIntoConstraints = false
addSubview(container)
containerHeightLayoutConstraint = container.heightAnchor.constraint(equalToConstant: 162).priority(.required - 1)
NSLayoutConstraint.activate([
container.topAnchor.constraint(equalTo: topAnchor),
container.leadingAnchor.constraint(equalTo: leadingAnchor),
trailingAnchor.constraint(equalTo: container.trailingAnchor),
bottomAnchor.constraint(equalTo: container.bottomAnchor),
containerHeightLayoutConstraint,
])
// will not influence full-screen playback
playerViewController.view.layer.masksToBounds = true
2021-03-11 12:06:15 +01:00
playerViewController.view.layer.cornerRadius = PlayerContainerView.cornerRadius
2021-03-10 07:36:28 +01:00
playerViewController.view.layer.cornerCurve = .continuous
// mediaType
mediaTypeIndicotorView.translatesAutoresizingMaskIntoConstraints = false
playerViewController.contentOverlayView!.addSubview(mediaTypeIndicotorView)
NSLayoutConstraint.activate([
mediaTypeIndicotorView.bottomAnchor.constraint(equalTo: playerViewController.contentOverlayView!.bottomAnchor),
mediaTypeIndicotorView.rightAnchor.constraint(equalTo: playerViewController.contentOverlayView!.rightAnchor),
mediaTypeIndicotorView.heightAnchor.constraint(equalToConstant: MediaTypeIndicotorView.indicatorViewSize.height).priority(.required - 1),
mediaTypeIndicotorView.widthAnchor.constraint(equalToConstant: MediaTypeIndicotorView.indicatorViewSize.width).priority(.required - 1),
])
contentWarningOverlayView.translatesAutoresizingMaskIntoConstraints = false
2021-03-11 12:06:15 +01:00
addSubview(contentWarningOverlayView)
NSLayoutConstraint.activate([
2021-03-11 12:06:15 +01:00
contentWarningOverlayView.topAnchor.constraint(equalTo: topAnchor),
contentWarningOverlayView.leadingAnchor.constraint(equalTo: leadingAnchor),
contentWarningOverlayView.trailingAnchor.constraint(equalTo: trailingAnchor),
contentWarningOverlayView.bottomAnchor.constraint(equalTo: bottomAnchor)
])
2021-03-11 12:06:15 +01:00
contentWarningOverlayView.delegate = self
mediaTypeIndicotorViewInContentWarningOverlay.translatesAutoresizingMaskIntoConstraints = false
contentWarningOverlayView.addSubview(mediaTypeIndicotorViewInContentWarningOverlay)
NSLayoutConstraint.activate([
mediaTypeIndicotorViewInContentWarningOverlay.bottomAnchor.constraint(equalTo: contentWarningOverlayView.bottomAnchor),
mediaTypeIndicotorViewInContentWarningOverlay.rightAnchor.constraint(equalTo: contentWarningOverlayView.rightAnchor),
mediaTypeIndicotorViewInContentWarningOverlay.heightAnchor.constraint(equalToConstant: MediaTypeIndicotorView.indicatorViewSize.height).priority(.required - 1),
mediaTypeIndicotorViewInContentWarningOverlay.widthAnchor.constraint(equalToConstant: MediaTypeIndicotorView.indicatorViewSize.width).priority(.required - 1),
])
2021-03-11 12:06:15 +01:00
}
}
// MARK: - ContentWarningOverlayViewDelegate
extension PlayerContainerView: ContentWarningOverlayViewDelegate {
func contentWarningOverlayViewDidPressed(_ contentWarningOverlayView: ContentWarningOverlayView) {
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function)
2021-03-11 12:06:15 +01:00
delegate?.playerContainerView(self, contentWarningOverlayViewDidPressed: contentWarningOverlayView)
2021-03-10 07:36:28 +01:00
}
}
2021-03-11 12:06:15 +01:00
extension PlayerContainerView {
2021-03-10 07:36:28 +01:00
func reset() {
// note: set playerViewController.player pause() and nil in data source configuration process make reloadData not break playing
playerViewController.willMove(toParent: nil)
playerViewController.view.removeFromSuperview()
playerViewController.removeFromParent()
container.subviews.forEach { subview in
subview.removeFromSuperview()
}
}
func setupPlayer(aspectRatio: CGSize, maxSize: CGSize, parent: UIViewController?) -> AVPlayerViewController {
reset()
touchBlockingView.translatesAutoresizingMaskIntoConstraints = false
container.addSubview(touchBlockingView)
NSLayoutConstraint.activate([
touchBlockingView.topAnchor.constraint(equalTo: container.topAnchor),
touchBlockingView.leadingAnchor.constraint(equalTo: container.leadingAnchor),
touchBlockingView.bottomAnchor.constraint(equalTo: container.bottomAnchor),
])
let rect = AVMakeRect(
aspectRatio: aspectRatio,
insideRect: CGRect(origin: .zero, size: maxSize)
)
parent?.addChild(playerViewController)
playerViewController.view.translatesAutoresizingMaskIntoConstraints = false
touchBlockingView.addSubview(playerViewController.view)
parent.flatMap { playerViewController.didMove(toParent: $0) }
NSLayoutConstraint.activate([
playerViewController.view.topAnchor.constraint(equalTo: touchBlockingView.topAnchor),
playerViewController.view.leadingAnchor.constraint(equalTo: touchBlockingView.leadingAnchor),
playerViewController.view.trailingAnchor.constraint(equalTo: touchBlockingView.trailingAnchor),
playerViewController.view.bottomAnchor.constraint(equalTo: touchBlockingView.bottomAnchor),
touchBlockingView.widthAnchor.constraint(equalToConstant: floor(rect.width)).priority(.required - 1),
])
containerHeightLayoutConstraint.constant = floor(rect.height)
containerHeightLayoutConstraint.isActive = true
bringSubviewToFront(mediaTypeIndicotorView)
2021-03-10 07:36:28 +01:00
return playerViewController
}
func setMediaKind(kind: VideoPlayerViewModel.Kind) {
mediaTypeIndicotorView.setMediaKind(kind: kind)
mediaTypeIndicotorViewInContentWarningOverlay.setMediaKind(kind: kind)
}
func setMediaIndicator(isHidden: Bool) {
mediaTypeIndicotorView.alpha = isHidden ? 0 : 1
mediaTypeIndicotorViewInContentWarningOverlay.alpha = isHidden ? 0 : 1
}
2021-03-10 07:36:28 +01:00
}