163 lines
5.5 KiB
Swift
163 lines
5.5 KiB
Swift
|
|
//
|
||
|
|
// AudioMixerViewController.swift
|
||
|
|
// XIONControlPanel
|
||
|
|
//
|
||
|
|
|
||
|
|
import UIKit
|
||
|
|
import WebKit
|
||
|
|
|
||
|
|
final class AudioMixerViewController: UIViewController, WKNavigationDelegate
|
||
|
|
{
|
||
|
|
static let controlsWidth: CGFloat = 54.0
|
||
|
|
|
||
|
|
var closeHandler: (() -> Void)?
|
||
|
|
|
||
|
|
private static let mixerURL = URL(string: "http://avmotu.localdomain/#touch-console")!
|
||
|
|
private static let accentColor = UIColor(red: 0.0, green: 0.95, blue: 0.95, alpha: 1.0)
|
||
|
|
|
||
|
|
private let _panelView = UIView(frame: .zero)
|
||
|
|
private let _webView = WKWebView(frame: .zero, configuration: WKWebViewConfiguration())
|
||
|
|
private let _closeButton = UIButton(type: .custom)
|
||
|
|
private let _refreshButton = UIButton(type: .custom)
|
||
|
|
private let _loadingProgressView = UIProgressView(progressViewStyle: .bar)
|
||
|
|
private var _progressObservation: NSKeyValueObservation?
|
||
|
|
|
||
|
|
override func loadView()
|
||
|
|
{
|
||
|
|
view = UIView(frame: .zero)
|
||
|
|
view.backgroundColor = .clear
|
||
|
|
view.clipsToBounds = false
|
||
|
|
}
|
||
|
|
|
||
|
|
override func viewDidLoad()
|
||
|
|
{
|
||
|
|
super.viewDidLoad()
|
||
|
|
|
||
|
|
_panelView.backgroundColor = .black
|
||
|
|
_panelView.layer.borderColor = Self.accentColor.withAlphaComponent(0.65).cgColor
|
||
|
|
_panelView.layer.borderWidth = 1.0
|
||
|
|
_panelView.layer.shadowColor = UIColor.black.cgColor
|
||
|
|
_panelView.layer.shadowOpacity = 0.95
|
||
|
|
_panelView.layer.shadowRadius = 116.0
|
||
|
|
_panelView.layer.shadowOffset = CGSize(width: -10.0, height: 0.0)
|
||
|
|
view.addSubview(_panelView)
|
||
|
|
|
||
|
|
_webView.navigationDelegate = self
|
||
|
|
_webView.isOpaque = false
|
||
|
|
_webView.backgroundColor = .black
|
||
|
|
_webView.scrollView.backgroundColor = .black
|
||
|
|
_webView.allowsBackForwardNavigationGestures = false
|
||
|
|
_panelView.addSubview(_webView)
|
||
|
|
|
||
|
|
_configureControlTab(_closeButton, accessibilityLabel: "Close Mixer")
|
||
|
|
_closeButton.setTitle("X", for: .normal)
|
||
|
|
_closeButton.titleLabel?.font = UIFont(name: "Orbitron-Medium", size: 18.0)
|
||
|
|
_closeButton.accessibilityIdentifier = "audio.close"
|
||
|
|
_closeButton.addTarget(self, action: #selector(_close), for: .touchUpInside)
|
||
|
|
view.addSubview(_closeButton)
|
||
|
|
|
||
|
|
_configureControlTab(_refreshButton, accessibilityLabel: "Refresh Mixer")
|
||
|
|
let refreshImage = UIImage(
|
||
|
|
systemName: "arrow.clockwise",
|
||
|
|
withConfiguration: UIImage.SymbolConfiguration(pointSize: 20.0, weight: .medium)
|
||
|
|
)
|
||
|
|
_refreshButton.setImage(refreshImage, for: .normal)
|
||
|
|
_refreshButton.tintColor = Self.accentColor
|
||
|
|
_refreshButton.accessibilityIdentifier = "audio.refresh"
|
||
|
|
_refreshButton.addTarget(self, action: #selector(_refresh), for: .touchUpInside)
|
||
|
|
view.addSubview(_refreshButton)
|
||
|
|
|
||
|
|
_loadingProgressView.progressTintColor = Self.accentColor
|
||
|
|
_loadingProgressView.trackTintColor = UIColor(white: 0.15, alpha: 1.0)
|
||
|
|
_panelView.addSubview(_loadingProgressView)
|
||
|
|
|
||
|
|
_progressObservation = _webView.observe(
|
||
|
|
\.estimatedProgress,
|
||
|
|
options: [.new]
|
||
|
|
) { [weak self] webView, _ in
|
||
|
|
guard let self else { return }
|
||
|
|
let progress = Float(webView.estimatedProgress)
|
||
|
|
self._loadingProgressView.setProgress(progress, animated: true)
|
||
|
|
self._loadingProgressView.isHidden = progress >= 1.0
|
||
|
|
}
|
||
|
|
|
||
|
|
_loadMixer()
|
||
|
|
}
|
||
|
|
|
||
|
|
override func viewDidLayoutSubviews()
|
||
|
|
{
|
||
|
|
super.viewDidLayoutSubviews()
|
||
|
|
|
||
|
|
let contentFrame = CGRect(
|
||
|
|
x: Self.controlsWidth,
|
||
|
|
y: 0.0,
|
||
|
|
width: max(0.0, view.bounds.width - Self.controlsWidth),
|
||
|
|
height: view.bounds.height
|
||
|
|
)
|
||
|
|
_panelView.frame = contentFrame
|
||
|
|
_panelView.layer.shadowPath = UIBezierPath(rect: _panelView.bounds).cgPath
|
||
|
|
_webView.frame = _panelView.bounds
|
||
|
|
_loadingProgressView.frame = CGRect(
|
||
|
|
x: 1.0,
|
||
|
|
y: 1.0,
|
||
|
|
width: max(0.0, _panelView.bounds.width - 2.0),
|
||
|
|
height: 2.0
|
||
|
|
)
|
||
|
|
|
||
|
|
let tabHeight: CGFloat = 54.0
|
||
|
|
let tabSpacing: CGFloat = 5.0
|
||
|
|
let tabTop: CGFloat = 16.0
|
||
|
|
_closeButton.frame = CGRect(
|
||
|
|
x: 0.0,
|
||
|
|
y: tabTop,
|
||
|
|
width: Self.controlsWidth + 1.0,
|
||
|
|
height: tabHeight
|
||
|
|
)
|
||
|
|
_refreshButton.frame = CGRect(
|
||
|
|
x: 0.0,
|
||
|
|
y: _closeButton.frame.maxY + tabSpacing,
|
||
|
|
width: Self.controlsWidth + 1.0,
|
||
|
|
height: tabHeight
|
||
|
|
)
|
||
|
|
|
||
|
|
view.bringSubviewToFront(_closeButton)
|
||
|
|
view.bringSubviewToFront(_refreshButton)
|
||
|
|
}
|
||
|
|
|
||
|
|
private func _configureControlTab(_ button: UIButton, accessibilityLabel: String)
|
||
|
|
{
|
||
|
|
button.backgroundColor = UIColor(white: 0.2, alpha: 1.0)
|
||
|
|
button.setTitleColor(Self.accentColor, for: .normal)
|
||
|
|
button.accessibilityTraits = .button
|
||
|
|
button.accessibilityLabel = accessibilityLabel
|
||
|
|
button.layer.borderColor = Self.accentColor.withAlphaComponent(0.65).cgColor
|
||
|
|
button.layer.borderWidth = 1.0
|
||
|
|
}
|
||
|
|
|
||
|
|
private func _loadMixer()
|
||
|
|
{
|
||
|
|
_loadingProgressView.isHidden = false
|
||
|
|
_loadingProgressView.progress = 0.0
|
||
|
|
let request = URLRequest(
|
||
|
|
url: Self.mixerURL,
|
||
|
|
cachePolicy: .reloadIgnoringLocalCacheData,
|
||
|
|
timeoutInterval: 30.0
|
||
|
|
)
|
||
|
|
_webView.load(request)
|
||
|
|
}
|
||
|
|
|
||
|
|
@objc private func _close()
|
||
|
|
{
|
||
|
|
closeHandler?()
|
||
|
|
}
|
||
|
|
|
||
|
|
@objc private func _refresh()
|
||
|
|
{
|
||
|
|
if _webView.url == nil {
|
||
|
|
_loadMixer()
|
||
|
|
} else {
|
||
|
|
_webView.reload()
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|