mastodon-ios/Mastodon/Scene/HomeTimeline/View/HomeTimelineNavigationBarTi...

211 lines
7.8 KiB
Swift

//
// HomeTimelineNavigationBarTitleView.swift
// Mastodon
//
// Created by sxiaojian on 2021/3/15.
//
import os.log
import UIKit
protocol HomeTimelineNavigationBarTitleViewDelegate: class {
func homeTimelineNavigationBarTitleView(_ titleView: HomeTimelineNavigationBarTitleView, buttonDidPressed sender: UIButton)
}
final class HomeTimelineNavigationBarTitleView: UIView {
let containerView = UIStackView()
let imageView = UIImageView()
let button = RoundedEdgesButton()
let label = UILabel()
// input
private var blockingState: HomeTimelineNavigationBarTitleViewModel.State?
weak var delegate: HomeTimelineNavigationBarTitleViewDelegate?
// output
private(set) var state: HomeTimelineNavigationBarTitleViewModel.State = .logoImage
override init(frame: CGRect) {
super.init(frame: frame)
_init()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
_init()
}
}
extension HomeTimelineNavigationBarTitleView {
private func _init() {
containerView.translatesAutoresizingMaskIntoConstraints = false
addSubview(containerView)
NSLayoutConstraint.activate([
containerView.topAnchor.constraint(equalTo: topAnchor),
containerView.leadingAnchor.constraint(equalTo: leadingAnchor),
containerView.trailingAnchor.constraint(equalTo: trailingAnchor),
containerView.bottomAnchor.constraint(equalTo: bottomAnchor),
])
containerView.addArrangedSubview(imageView)
button.translatesAutoresizingMaskIntoConstraints = false
containerView.addArrangedSubview(button)
NSLayoutConstraint.activate([
button.heightAnchor.constraint(equalToConstant: 24).priority(.defaultHigh)
])
containerView.addArrangedSubview(label)
configure(state: .logoImage)
button.addTarget(self, action: #selector(HomeTimelineNavigationBarTitleView.buttonDidPressed(_:)), for: .touchUpInside)
}
}
extension HomeTimelineNavigationBarTitleView {
@objc private func buttonDidPressed(_ sender: UIButton) {
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function)
delegate?.homeTimelineNavigationBarTitleView(self, buttonDidPressed: sender)
}
}
extension HomeTimelineNavigationBarTitleView {
func resetContainer() {
imageView.isHidden = true
button.isHidden = true
label.isHidden = true
}
func configure(state: HomeTimelineNavigationBarTitleViewModel.State) {
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: configure title view: %s", ((#file as NSString).lastPathComponent), #line, #function, state.rawValue)
self.state = state
// check state block or not
guard blockingState == nil else {
return
}
resetContainer()
switch state {
case .logoImage:
imageView.tintColor = Asset.Colors.Label.primary.color
imageView.image = Asset.Asset.mastodonTextLogo.image.withRenderingMode(.alwaysTemplate)
imageView.contentMode = .center
imageView.isHidden = false
case .newPostButton:
configureButton(
title: L10n.Scene.HomeTimeline.NavigationBarState.newPosts,
textColor: .white,
backgroundColor: Asset.Colors.Button.normal.color
)
button.isHidden = false
case .offlineButton:
configureButton(
title: L10n.Scene.HomeTimeline.NavigationBarState.offline,
textColor: .white,
backgroundColor: Asset.Colors.Background.danger.color
)
button.isHidden = false
case .publishingPostLabel:
label.font = .systemFont(ofSize: 17, weight: .semibold)
label.textColor = Asset.Colors.Label.primary.color
label.text = L10n.Scene.HomeTimeline.NavigationBarState.publishing
label.textAlignment = .center
label.isHidden = false
case .publishedButton:
blockingState = state
configureButton(
title: L10n.Scene.HomeTimeline.NavigationBarState.published,
textColor: .white,
backgroundColor: Asset.Colors.successGreen.color
)
button.isHidden = false
let presentDuration: TimeInterval = 0.33
let scaleAnimator = UIViewPropertyAnimator(duration: presentDuration, timingParameters: UISpringTimingParameters())
button.transform = CGAffineTransform(scaleX: 0.5, y: 0.5)
scaleAnimator.addAnimations {
self.button.transform = .identity
}
let alphaAnimator = UIViewPropertyAnimator(duration: presentDuration, curve: .easeInOut)
button.alpha = 0.3
alphaAnimator.addAnimations {
self.button.alpha = 1
}
scaleAnimator.startAnimation()
alphaAnimator.startAnimation()
let dismissDuration: TimeInterval = 3
let dissolveAnimator = UIViewPropertyAnimator(duration: dismissDuration, curve: .easeInOut)
dissolveAnimator.addAnimations({
self.button.alpha = 0
}, delayFactor: 0.9) // at 2.7s
dissolveAnimator.addCompletion { _ in
self.blockingState = nil
self.configure(state: self.state)
self.button.alpha = 1
}
dissolveAnimator.startAnimation()
}
}
private func configureButton(title: String, textColor: UIColor, backgroundColor: UIColor) {
button.setBackgroundImage(.placeholder(color: backgroundColor), for: .normal)
button.setBackgroundImage(.placeholder(color: backgroundColor.withAlphaComponent(0.5)), for: .highlighted)
button.setTitleColor(textColor, for: .normal)
button.setTitleColor(textColor.withAlphaComponent(0.5), for: .highlighted)
button.setTitle(title, for: .normal)
button.contentEdgeInsets = UIEdgeInsets(top: 1, left: 16, bottom: 1, right: 16)
button.titleLabel?.font = .systemFont(ofSize: 15, weight: .bold)
}
}
#if canImport(SwiftUI) && DEBUG
import SwiftUI
struct HomeTimelineNavigationBarTitleView_Previews: PreviewProvider {
static var previews: some View {
Group {
UIViewPreview(width: 375) {
let titleView = HomeTimelineNavigationBarTitleView()
titleView.configure(state: .logoImage)
return titleView
}
.previewLayout(.fixed(width: 375, height: 44))
UIViewPreview(width: 150) {
let titleView = HomeTimelineNavigationBarTitleView()
titleView.configure(state: .newPostButton)
return titleView
}
.previewLayout(.fixed(width: 150, height: 24))
UIViewPreview(width: 120) {
let titleView = HomeTimelineNavigationBarTitleView()
titleView.configure(state: .offlineButton)
return titleView
}
.previewLayout(.fixed(width: 120, height: 24))
UIViewPreview(width: 375) {
let titleView = HomeTimelineNavigationBarTitleView()
titleView.configure(state: .publishingPostLabel)
return titleView
}
.previewLayout(.fixed(width: 375, height: 44))
UIViewPreview(width: 120) {
let titleView = HomeTimelineNavigationBarTitleView()
titleView.configure(state: .publishedButton)
return titleView
}
.previewLayout(.fixed(width: 120, height: 24))
}
}
}
#endif