2023-02-14 22:44:44 +04:00

186 lines
5.6 KiB
Swift

import Foundation
import UIKit
import Display
import SwiftSignalKit
private let phrases = [
"Вітаю",
"你好",
"Hello",
"سلام",
"Bonjour",
"Guten tag",
"שלום",
"नमस्ते",
"Ciao",
"こんにちは",
"Hei",
"Olá",
"Привет",
"Zdravo",
"Hola",
"Привіт",
"Salom",
"Halo"
]
private var simultaneousDisplayCount = 13
private let referenceWidth: CGFloat = 1180
private let positions: [CGPoint] = [
CGPoint(x: 315.0, y: 83.0),
CGPoint(x: 676.0, y: 18.0),
CGPoint(x: 880.0, y: 130.0),
CGPoint(x: 90.0, y: 214.0),
CGPoint(x: 550.0, y: 150.0),
CGPoint(x: 1130.0, y: 220.0),
CGPoint(x: 220.0, y: 440.0),
CGPoint(x: 1080.0, y: 350.0),
CGPoint(x: 85.0, y: 630.0),
CGPoint(x: 1180.0, y: 550.0),
CGPoint(x: 150.0, y: 810.0),
CGPoint(x: 1010.0, y: 770.0),
CGPoint(x: 40.0, y: 1000.0),
CGPoint(x: 1130.0, y: 1000.0)
]
final class HelloView: UIView, PhoneDemoDecorationView {
private var activePhrases = Set<Int>()
private var activePositions = Set<Int>()
private var containerView: UIView
override init(frame: CGRect) {
self.containerView = UIView()
super.init(frame: frame)
self.addSubview(self.containerView)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private var didSetup = false
func setupAnimations() {
guard self.activePhrases.isEmpty, self.visible else {
return
}
self.didSetup = true
var ids: [Int] = []
for i in 0 ..< phrases.count {
ids.append(i)
}
ids.shuffle()
let phraseIds = Array(self.availablePhraseIds()).shuffled()
let positionIds = Array(self.availablePositionIds()).shuffled()
for i in 0 ..< simultaneousDisplayCount {
let delay: Double = Double.random(in: 0.0 ..< 0.8)
Queue.mainQueue().after(delay) {
self.spawnPhrase(phraseIds[i], positionIndex: positionIds[i])
}
}
}
func availablePhraseIds() -> Set<Int> {
var ids = Set<Int>()
for i in 0 ..< phrases.count {
ids.insert(i)
}
for id in self.activePhrases {
ids.remove(id)
}
return ids
}
func availablePositionIds() -> Set<Int> {
var ids = Set<Int>()
for i in 0 ..< positions.count {
ids.insert(i)
}
for id in self.activePositions {
ids.remove(id)
}
return ids
}
func spawnNextPhrase() {
let phraseIds = Array(self.availablePhraseIds()).shuffled()
let positionIds = Array(self.availablePositionIds()).shuffled()
if let phrase = phraseIds.first, let position = positionIds.first {
self.spawnPhrase(phrase, positionIndex: position)
}
}
func spawnPhrase(_ index: Int, positionIndex: Int) {
let view = UILabel()
view.alpha = 0.0
view.text = phrases[index]
view.font = Font.with(size: 24.0, design: .round, weight: .semibold, traits: [])
view.textColor = UIColor(rgb: 0xffffff, alpha: CGFloat.random(in: 0.4 ... 0.6))
view.layer.compositingFilter = "softLightBlendMode"
view.sizeToFit()
view.center = self.positionForIndex(positionIndex)
self.activePhrases.insert(index)
self.activePositions.insert(positionIndex)
let duration: Double = Double.random(in: 1.75...2.25)
view.layer.animateKeyframes(values: [0.0, 1.0, 0.0] as [NSNumber], duration: duration, keyPath: "opacity", removeOnCompletion: false, completion: { [weak view, weak self] _ in
if let self {
self.activePhrases.remove(index)
self.activePositions.remove(positionIndex)
view?.removeFromSuperview()
self.spawnNextPhrase()
}
})
view.layer.animateScale(from: CGFloat.random(in: 0.4 ..< 0.6), to: CGFloat.random(in: 0.9 ..< 1.2), duration: duration, removeOnCompletion: false)
self.containerView.addSubview(view)
}
func positionForIndex(_ index: Int) -> CGPoint {
var position = positions[index]
let spread: CGPoint = CGPoint(x: 30.0, y: 5.0)
position.x = (self.frame.width - self.frame.height) / 2.0 + position.x / referenceWidth * self.frame.height + CGFloat.random(in: -spread.x ... spread.x)
position.y = position.y / referenceWidth * self.frame.height + CGFloat.random(in: -spread.y ... spread.y)
return position
}
private var visible = false
func setVisible(_ visible: Bool) {
guard self.visible != visible else {
return
}
self.visible = visible
if visible {
self.setupAnimations()
} else {
self.didSetup = false
}
let transition = ContainedViewLayoutTransition.animated(duration: 0.3, curve: .linear)
transition.updateAlpha(layer: self.containerView.layer, alpha: visible ? 1.0 : 0.0, completion: { [weak self] finished in
if let strongSelf = self, finished && !visible && !strongSelf.visible {
for view in strongSelf.containerView.subviews {
view.removeFromSuperview()
}
}
})
}
func resetAnimation() {
}
override func layoutSubviews() {
super.layoutSubviews()
self.containerView.frame = CGRect(origin: .zero, size: self.frame.size)
}
}