mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
139 lines
6.1 KiB
Swift
139 lines
6.1 KiB
Swift
import Foundation
|
|
import UIKit
|
|
import Display
|
|
import ComponentFlow
|
|
import TelegramPresentationData
|
|
|
|
final class WarpView: UIView {
|
|
private final class WarpPartView: UIView {
|
|
let cloneView: PortalView
|
|
|
|
init?(contentView: PortalSourceView) {
|
|
guard let cloneView = PortalView(matchPosition: false) else {
|
|
return nil
|
|
}
|
|
self.cloneView = cloneView
|
|
|
|
super.init(frame: CGRect())
|
|
|
|
self.layer.anchorPoint = CGPoint(x: 0.5, y: 0.0)
|
|
|
|
self.clipsToBounds = true
|
|
self.addSubview(cloneView.view)
|
|
contentView.addPortal(view: cloneView)
|
|
}
|
|
|
|
required init?(coder: NSCoder) {
|
|
fatalError("init(coder:) has not been implemented")
|
|
}
|
|
|
|
func update(containerSize: CGSize, rect: CGRect, transition: ComponentTransition) {
|
|
transition.setFrame(view: self.cloneView.view, frame: CGRect(origin: CGPoint(x: -rect.minX, y: -rect.minY), size: CGSize(width: containerSize.width, height: containerSize.height)))
|
|
}
|
|
}
|
|
|
|
let contentView: PortalSourceView
|
|
|
|
private let clippingView: UIView
|
|
|
|
private var warpViews: [WarpPartView] = []
|
|
private let warpMaskContainer: UIView
|
|
private let warpMaskGradientLayer: SimpleGradientLayer
|
|
|
|
override init(frame: CGRect) {
|
|
self.contentView = PortalSourceView()
|
|
self.clippingView = UIView()
|
|
|
|
self.warpMaskContainer = UIView()
|
|
self.warpMaskGradientLayer = SimpleGradientLayer()
|
|
self.warpMaskContainer.layer.mask = self.warpMaskGradientLayer
|
|
|
|
super.init(frame: frame)
|
|
|
|
self.clippingView.addSubview(self.contentView)
|
|
|
|
self.clippingView.clipsToBounds = true
|
|
self.addSubview(self.clippingView)
|
|
self.addSubview(self.warpMaskContainer)
|
|
|
|
for _ in 0 ..< 8 {
|
|
if let warpView = WarpPartView(contentView: self.contentView) {
|
|
self.warpViews.append(warpView)
|
|
self.warpMaskContainer.addSubview(warpView)
|
|
}
|
|
}
|
|
}
|
|
|
|
required init?(coder: NSCoder) {
|
|
fatalError("init(coder:) has not been implemented")
|
|
}
|
|
|
|
func update(size: CGSize, topInset: CGFloat, warpHeight: CGFloat, theme: PresentationTheme, transition: ComponentTransition) {
|
|
transition.setFrame(view: self.contentView, frame: CGRect(origin: CGPoint(), size: size))
|
|
|
|
let allItemsHeight = warpHeight * 0.5
|
|
for i in 0 ..< self.warpViews.count {
|
|
let itemHeight = warpHeight / CGFloat(self.warpViews.count)
|
|
let itemFraction = CGFloat(i + 1) / CGFloat(self.warpViews.count)
|
|
let _ = itemHeight
|
|
|
|
let da = CGFloat.pi * 0.5 / CGFloat(self.warpViews.count)
|
|
let alpha = CGFloat.pi * 0.5 - itemFraction * CGFloat.pi * 0.5
|
|
let endPoint = CGPoint(x: cos(alpha), y: sin(alpha))
|
|
let prevAngle = alpha + da
|
|
let prevPt = CGPoint(x: cos(prevAngle), y: sin(prevAngle))
|
|
var angle: CGFloat
|
|
angle = -atan2(endPoint.y - prevPt.y, endPoint.x - prevPt.x)
|
|
|
|
let itemLengthVector = CGPoint(x: endPoint.x - prevPt.x, y: endPoint.y - prevPt.y)
|
|
let itemLength = sqrt(itemLengthVector.x * itemLengthVector.x + itemLengthVector.y * itemLengthVector.y) * warpHeight * 0.5
|
|
let _ = itemLength
|
|
|
|
var transform: CATransform3D
|
|
transform = CATransform3DIdentity
|
|
transform.m34 = 1.0 / 240.0
|
|
|
|
transform = CATransform3DTranslate(transform, 0.0, prevPt.x * allItemsHeight, (1.0 - prevPt.y) * allItemsHeight)
|
|
transform = CATransform3DRotate(transform, angle, 1.0, 0.0, 0.0)
|
|
|
|
let positionY = size.height - allItemsHeight + 4.0 + CGFloat(i) * itemLength
|
|
let rect = CGRect(origin: CGPoint(x: 0.0, y: positionY), size: CGSize(width: size.width, height: itemLength))
|
|
transition.setPosition(view: self.warpViews[i], position: CGPoint(x: rect.midX, y: 4.0))
|
|
transition.setBounds(view: self.warpViews[i], bounds: CGRect(origin: CGPoint(), size: CGSize(width: size.width, height: itemLength)))
|
|
transition.setTransform(view: self.warpViews[i], transform: transform)
|
|
self.warpViews[i].update(containerSize: size, rect: rect, transition: transition)
|
|
}
|
|
|
|
let clippingTopInset: CGFloat = topInset
|
|
let frame = CGRect(origin: CGPoint(x: 0.0, y: clippingTopInset), size: CGSize(width: size.width, height: -clippingTopInset + size.height - 21.0))
|
|
transition.setPosition(view: self.clippingView, position: frame.center)
|
|
transition.setBounds(view: self.clippingView, bounds: CGRect(origin: CGPoint(x: 0.0, y: clippingTopInset), size: frame.size))
|
|
self.clippingView.clipsToBounds = true
|
|
|
|
transition.setFrame(view: self.warpMaskContainer, frame: CGRect(origin: CGPoint(x: 0.0, y: size.height - allItemsHeight), size: CGSize(width: size.width, height: allItemsHeight)))
|
|
|
|
var locations: [NSNumber] = []
|
|
var colors: [CGColor] = []
|
|
let numStops = 6
|
|
for i in 0 ..< numStops {
|
|
let step = CGFloat(i) / CGFloat(numStops - 1)
|
|
locations.append(step as NSNumber)
|
|
colors.append(UIColor.black.withAlphaComponent(1.0 - step * step).cgColor)
|
|
}
|
|
|
|
let gradientHeight: CGFloat = 6.0
|
|
self.warpMaskGradientLayer.startPoint = CGPoint(x: 0.0, y: (allItemsHeight - gradientHeight) / allItemsHeight)
|
|
self.warpMaskGradientLayer.endPoint = CGPoint(x: 0.0, y: 1.0)
|
|
|
|
self.warpMaskGradientLayer.locations = locations
|
|
self.warpMaskGradientLayer.colors = colors
|
|
self.warpMaskGradientLayer.type = .axial
|
|
|
|
transition.setFrame(layer: self.warpMaskGradientLayer, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: size.width, height: allItemsHeight)))
|
|
}
|
|
|
|
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
|
return self.contentView.hitTest(point, with: event)
|
|
}
|
|
}
|