mastodon-ios/Mastodon/Scene/MainTab/MainTabBarController+Wizard...

135 lines
4.0 KiB
Swift

//
// MainTabBarController+Wizard.swift
// Mastodon
//
// Created by Cirno MainasuK on 2021-9-15.
//
import os.log
import UIKit
protocol WizardDelegate: AnyObject {
func spotlight(item: MainTabBarController.Wizard.Item) -> UIBezierPath
func layoutWizardCard(_ wizard: MainTabBarController.Wizard, item: MainTabBarController.Wizard.Item)
}
extension MainTabBarController {
class Wizard {
let logger = Logger(subsystem: "Wizard", category: "UI")
weak var delegate: WizardDelegate?
private(set) var items: [Item]
let backgroundView: UIView = {
let view = UIView()
view.backgroundColor = UIColor.black.withAlphaComponent(0.7)
return view
}()
init() {
var items: [Item] = []
if !UserDefaults.shared.didShowMultipleAccountSwitchWizard {
items.append(.multipleAccountSwitch)
}
self.items = items
let backgroundTapGestureRecognizer = UITapGestureRecognizer.singleTapGestureRecognizer
backgroundTapGestureRecognizer.addTarget(self, action: #selector(MainTabBarController.Wizard.backgroundTapGestureRecognizerHandler(_:)))
backgroundView.addGestureRecognizer(backgroundTapGestureRecognizer)
}
}
}
extension MainTabBarController.Wizard {
enum Item {
case multipleAccountSwitch
var title: String {
return L10n.Scene.Wizard.newInMastodon
}
var description: String {
switch self {
case .multipleAccountSwitch:
return L10n.Scene.Wizard.multipleAccountSwitchIntroDescription
}
}
func markAsRead() {
switch self {
case .multipleAccountSwitch:
UserDefaults.shared.didShowMultipleAccountSwitchWizard = true
}
}
}
}
extension MainTabBarController.Wizard {
func setup(in view: UIView) {
assert(delegate != nil, "need set delegate before use")
backgroundView.frame = view.bounds
backgroundView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(backgroundView)
NSLayoutConstraint.activate([
backgroundView.topAnchor.constraint(equalTo: view.topAnchor),
backgroundView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
backgroundView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
backgroundView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
])
}
func consume() {
guard !items.isEmpty else {
backgroundView.removeFromSuperview()
return
}
let item = items.removeFirst()
perform(item: item)
}
private func perform(item: Item) {
guard let delegate = delegate else {
assertionFailure()
return
}
// prepare for reuse
prepareForReuse()
// set wizard item read
item.markAsRead()
// add spotlight
let spotlight = delegate.spotlight(item: item)
let maskLayer = CAShapeLayer()
let path = UIBezierPath(rect: backgroundView.bounds)
path.append(spotlight)
maskLayer.fillRule = .evenOdd
maskLayer.path = path.cgPath
backgroundView.layer.mask = maskLayer
// layout wizard card
delegate.layoutWizardCard(self, item: item)
}
private func prepareForReuse() {
backgroundView.subviews.forEach { subview in
subview.removeFromSuperview()
}
backgroundView.mask = nil
backgroundView.layer.mask = nil
}
}
extension MainTabBarController.Wizard {
@objc private func backgroundTapGestureRecognizerHandler(_ sender: UITapGestureRecognizer) {
logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public)")
consume()
}
}