mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
184 lines
8.2 KiB
Swift
184 lines
8.2 KiB
Swift
import Foundation
|
|
import UIKit
|
|
import Display
|
|
import ComponentFlow
|
|
import PagerComponent
|
|
import TelegramPresentationData
|
|
import TelegramCore
|
|
import Postbox
|
|
|
|
final class EntityKeyboardTopContainerPanelEnvironment: Equatable {
|
|
let visibilityFractionUpdated: ActionSlot<(CGFloat, Transition)>
|
|
|
|
init(
|
|
visibilityFractionUpdated: ActionSlot<(CGFloat, Transition)>
|
|
) {
|
|
self.visibilityFractionUpdated = visibilityFractionUpdated
|
|
}
|
|
|
|
static func ==(lhs: EntityKeyboardTopContainerPanelEnvironment, rhs: EntityKeyboardTopContainerPanelEnvironment) -> Bool {
|
|
if lhs.visibilityFractionUpdated !== rhs.visibilityFractionUpdated {
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
}
|
|
|
|
final class EntityKeyboardTopContainerPanelComponent: Component {
|
|
typealias EnvironmentType = PagerComponentPanelEnvironment<EntityKeyboardTopContainerPanelEnvironment>
|
|
|
|
let theme: PresentationTheme
|
|
|
|
init(
|
|
theme: PresentationTheme
|
|
) {
|
|
self.theme = theme
|
|
}
|
|
|
|
static func ==(lhs: EntityKeyboardTopContainerPanelComponent, rhs: EntityKeyboardTopContainerPanelComponent) -> Bool {
|
|
if lhs.theme !== rhs.theme {
|
|
return false
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
private final class PanelView {
|
|
let view = ComponentHostView<EntityKeyboardTopContainerPanelEnvironment>()
|
|
let visibilityFractionUpdated = ActionSlot<(CGFloat, Transition)>()
|
|
}
|
|
|
|
final class View: UIView {
|
|
private var panelViews: [AnyHashable: PanelView] = [:]
|
|
|
|
private var component: EntityKeyboardTopContainerPanelComponent?
|
|
private var panelEnvironment: PagerComponentPanelEnvironment<EntityKeyboardTopContainerPanelEnvironment>?
|
|
private weak var state: EmptyComponentState?
|
|
|
|
private var visibilityFraction: CGFloat = 1.0
|
|
|
|
override init(frame: CGRect) {
|
|
super.init(frame: frame)
|
|
}
|
|
|
|
required init?(coder: NSCoder) {
|
|
fatalError("init(coder:) has not been implemented")
|
|
}
|
|
|
|
func update(component: EntityKeyboardTopContainerPanelComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<EnvironmentType>, transition: Transition) -> CGSize {
|
|
let intrinsicHeight: CGFloat = 41.0
|
|
let height = intrinsicHeight
|
|
|
|
let panelEnvironment = environment[PagerComponentPanelEnvironment.self].value
|
|
|
|
var transitionOffsetFraction: CGFloat = 0.0
|
|
if case .none = transition.animation {
|
|
} else if let previousPanelEnvironment = self.panelEnvironment, let previousActiveContentId = previousPanelEnvironment.activeContentId, let activeContentId = panelEnvironment.activeContentId, previousActiveContentId != activeContentId {
|
|
if let previousIndex = panelEnvironment.contentTopPanels.firstIndex(where: { $0.id == previousActiveContentId }), let index = panelEnvironment.contentTopPanels.firstIndex(where: { $0.id == activeContentId }), previousIndex != index {
|
|
if index < previousIndex {
|
|
transitionOffsetFraction = -1.0
|
|
} else {
|
|
transitionOffsetFraction = 1.0
|
|
}
|
|
}
|
|
}
|
|
|
|
self.component = component
|
|
self.panelEnvironment = panelEnvironment
|
|
self.state = state
|
|
|
|
var validPanelIds = Set<AnyHashable>()
|
|
let visibleBounds = CGRect(origin: CGPoint(), size: CGSize(width: availableSize.width, height: intrinsicHeight))
|
|
if let centralId = panelEnvironment.activeContentId, let centralIndex = panelEnvironment.contentTopPanels.firstIndex(where: { $0.id == centralId }) {
|
|
for index in 0 ..< panelEnvironment.contentTopPanels.count {
|
|
let panel = panelEnvironment.contentTopPanels[index]
|
|
let indexOffset = index - centralIndex
|
|
|
|
let panelFrame = CGRect(origin: CGPoint(x: CGFloat(indexOffset) * availableSize.width, y: 0.0), size: CGSize(width: availableSize.width, height: intrinsicHeight))
|
|
|
|
let isInBounds = visibleBounds.intersects(panelFrame)
|
|
let isPartOfTransition: Bool
|
|
if !transitionOffsetFraction.isZero && self.panelViews[panel.id] != nil {
|
|
isPartOfTransition = true
|
|
} else {
|
|
isPartOfTransition = false
|
|
}
|
|
|
|
if isInBounds || isPartOfTransition {
|
|
validPanelIds.insert(panel.id)
|
|
|
|
var panelTransition = transition
|
|
let panelView: PanelView
|
|
if let current = self.panelViews[panel.id] {
|
|
panelView = current
|
|
} else {
|
|
panelTransition = .immediate
|
|
panelView = PanelView()
|
|
self.panelViews[panel.id] = panelView
|
|
self.addSubview(panelView.view)
|
|
}
|
|
|
|
let _ = panelView.view.update(
|
|
transition: panelTransition,
|
|
component: panel.component,
|
|
environment: {
|
|
EntityKeyboardTopContainerPanelEnvironment(
|
|
visibilityFractionUpdated: panelView.visibilityFractionUpdated
|
|
)
|
|
},
|
|
containerSize: panelFrame.size
|
|
)
|
|
if isInBounds {
|
|
transition.animatePosition(view: panelView.view, from: CGPoint(x: transitionOffsetFraction * availableSize.width, y: 0.0), to: CGPoint(), additive: true, completion: nil)
|
|
}
|
|
panelTransition.setFrame(view: panelView.view, frame: panelFrame, completion: { [weak self] completed in
|
|
if isPartOfTransition && completed {
|
|
self?.state?.updated(transition: .immediate)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
}
|
|
var removedPanelIds: [AnyHashable] = []
|
|
for (id, panelView) in self.panelViews {
|
|
if !validPanelIds.contains(id) {
|
|
removedPanelIds.append(id)
|
|
panelView.view.removeFromSuperview()
|
|
}
|
|
}
|
|
for id in removedPanelIds {
|
|
self.panelViews.removeValue(forKey: id)
|
|
}
|
|
|
|
environment[PagerComponentPanelEnvironment.self].value.visibilityFractionUpdated.connect { [weak self] (fraction, transition) in
|
|
guard let strongSelf = self else {
|
|
return
|
|
}
|
|
strongSelf.updateVisibilityFraction(value: fraction, transition: transition)
|
|
}
|
|
|
|
return CGSize(width: availableSize.width, height: height)
|
|
}
|
|
|
|
private func updateVisibilityFraction(value: CGFloat, transition: Transition) {
|
|
if self.visibilityFraction == value {
|
|
return
|
|
}
|
|
|
|
self.visibilityFraction = value
|
|
for (_, panelView) in self.panelViews {
|
|
panelView.visibilityFractionUpdated.invoke((value, transition))
|
|
transition.setSublayerTransform(view: panelView.view, transform: CATransform3DMakeTranslation(0.0, -panelView.view.bounds.height / 2.0 * (1.0 - value), 0.0))
|
|
}
|
|
}
|
|
}
|
|
|
|
func makeView() -> View {
|
|
return View(frame: CGRect())
|
|
}
|
|
|
|
func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<EnvironmentType>, transition: Transition) -> CGSize {
|
|
return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition)
|
|
}
|
|
}
|