RetroArch/pkg/apple/HelperBar/HelperBarViewController.swift

164 lines
5.7 KiB
Swift

//
// HelperBarViewController.swift
// RetroArchiOS
//
// Created by Yoshi Sugawara on 2/27/22.
// Copyright © 2022 RetroArch. All rights reserved.
//
@available(iOS 13, *)
class HelperBarViewController: UIViewController {
var viewModel = HelperBarViewModel()
private let indicatorImageView: UIImageView = {
let imageView = UIImageView(frame: .zero)
imageView.image = UIImage(systemName: "arrow.down.circle")
imageView.tintColor = .white
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.alpha = 0
imageView.isUserInteractionEnabled = true
return imageView
}()
private let navigationBar: UINavigationBar = {
let navBar = UINavigationBar()
navBar.barTintColor = .black
navBar.isTranslucent = true
navBar.alpha = 0.7
navBar.tintColor = .white
navBar.isHidden = true
return navBar
}()
override func viewDidLoad() {
viewModel.delegate = self
setupViews()
setupBarItems()
}
override func viewDidAppear(_ animated: Bool) {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { [weak self] in
self?.showIndicatorAndFadeAway()
}
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { [weak self] in
self?.showIndicatorAndFadeAway()
}
}
private func setupViews() {
indicatorImageView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(indicatorImageView)
indicatorImageView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 4).isActive = true
indicatorImageView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 40).isActive = true
indicatorImageView.heightAnchor.constraint(equalToConstant: 40).isActive = true
indicatorImageView.widthAnchor.constraint(equalTo: indicatorImageView.heightAnchor).isActive = true
view.addSubview(navigationBar)
navigationBar.translatesAutoresizingMaskIntoConstraints = false
navigationBar.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
navigationBar.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
navigationBar.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
let tap = UITapGestureRecognizer(target: self, action: #selector(didTap(_:)))
tap.delegate = self
view.addGestureRecognizer(tap)
view.isUserInteractionEnabled = true
let indicatorTap = UITapGestureRecognizer(target: self, action: #selector(didTapIndicator(_:)))
indicatorImageView.addGestureRecognizer(indicatorTap)
navigationBar.delegate = self
}
private func setupBarItems() {
let barButtonItems = viewModel.createBarButtonItems()
let navItem = UINavigationItem()
navItem.leftBarButtonItems = barButtonItems
navigationBar.items = [navItem]
updateBarItems()
}
private func updateBarItems() {
guard let navItem = navigationBar.items?[0],
let barButtonItems = navItem.leftBarButtonItems else {
return
}
for barButtonItem in barButtonItems {
guard let helperBarItem = viewModel.barItemMapping[barButtonItem] else {
continue
}
if helperBarItem.isSelected {
barButtonItem.image = helperBarItem.selectedImage
if let tintColor = helperBarItem.tintColorOnSelection {
barButtonItem.tintColor = tintColor
} else {
barButtonItem.tintColor = nil
}
} else {
barButtonItem.image = helperBarItem.image
barButtonItem.tintColor = nil
}
}
}
private func showIndicatorAndFadeAway() {
UIView.animateKeyframes(withDuration: 4.0, delay: 0) {
UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration: 1/7) { [weak self] in
self?.indicatorImageView.alpha = 1.0
}
UIView.addKeyframe(withRelativeStartTime: 1/3, relativeDuration: 6/7) { [weak self] in
self?.indicatorImageView.alpha = 0.0
}
}
}
var tappedIndicator = false
@objc func didTap(_ sender: UITapGestureRecognizer) {
let point = sender.location(in: view)
guard point.y <= 60 else { return } // detect top portion of view only
if point.x <= 60 {
indicatorImageView.layer.removeAllAnimations()
indicatorImageView.alpha = 1.0
tappedIndicator = false
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) { [weak self] in
if !(self?.tappedIndicator ?? false) {
self?.showIndicatorAndFadeAway()
}
}
}
}
@objc func didTapIndicator(_ sender: UITapGestureRecognizer) {
viewModel.didInteractWithBar = true
indicatorImageView.layer.removeAllAnimations()
indicatorImageView.alpha = 0
tappedIndicator = true
}
}
@available(iOS 13, *)
extension HelperBarViewController: UIGestureRecognizerDelegate {
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
true
}
}
@available(iOS 13, *)
extension HelperBarViewController: HelperBarViewModelDelegate {
func setNavigationBarHidden(_ isHidden: Bool) {
navigationBar.isHidden = isHidden
}
func updateNavigationBarItems() {
updateBarItems()
}
}
@available(iOS 13, *)
extension HelperBarViewController: UINavigationBarDelegate {
func position(for bar: UIBarPositioning) -> UIBarPosition {
return .topAttached
}
}