mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-01 04:08:07 +00:00
281 lines
13 KiB
Swift
281 lines
13 KiB
Swift
import Foundation
|
|
import UIKit
|
|
import Display
|
|
import TelegramPresentationData
|
|
import ComponentFlow
|
|
import GlassBackgroundComponent
|
|
|
|
public final class GlassControlPanelComponent: Component {
|
|
public final class Item: Equatable {
|
|
public let items: [GlassControlGroupComponent.Item]
|
|
public let background: GlassControlGroupComponent.Background
|
|
|
|
public init(items: [GlassControlGroupComponent.Item], background: GlassControlGroupComponent.Background) {
|
|
self.items = items
|
|
self.background = background
|
|
}
|
|
|
|
public static func ==(lhs: Item, rhs: Item) -> Bool {
|
|
if lhs.items != rhs.items {
|
|
return false
|
|
}
|
|
if lhs.background != rhs.background {
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
}
|
|
|
|
public let theme: PresentationTheme
|
|
public let leftItem: Item?
|
|
public let rightItem: Item?
|
|
public let centralItem: Item?
|
|
|
|
public init(
|
|
theme: PresentationTheme,
|
|
leftItem: Item?,
|
|
centralItem: Item?,
|
|
rightItem: Item?
|
|
) {
|
|
self.theme = theme
|
|
self.leftItem = leftItem
|
|
self.centralItem = centralItem
|
|
self.rightItem = rightItem
|
|
}
|
|
|
|
public static func ==(lhs: GlassControlPanelComponent, rhs: GlassControlPanelComponent) -> Bool {
|
|
if lhs.theme !== rhs.theme {
|
|
return false
|
|
}
|
|
if lhs.leftItem != rhs.leftItem {
|
|
return false
|
|
}
|
|
if lhs.centralItem != rhs.centralItem {
|
|
return false
|
|
}
|
|
if lhs.rightItem != rhs.rightItem {
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
public final class View: UIView {
|
|
private let glassContainerView: GlassBackgroundContainerView
|
|
|
|
private var leftItemComponent: ComponentView<Empty>?
|
|
private var centralItemComponent: ComponentView<Empty>?
|
|
private var rightItemComponent: ComponentView<Empty>?
|
|
|
|
private var component: GlassControlPanelComponent?
|
|
private weak var state: EmptyComponentState?
|
|
|
|
public var leftItemView: GlassControlGroupComponent.View? {
|
|
return self.leftItemComponent?.view as? GlassControlGroupComponent.View
|
|
}
|
|
|
|
public var centerItemView: GlassControlGroupComponent.View? {
|
|
return self.centralItemComponent?.view as? GlassControlGroupComponent.View
|
|
}
|
|
|
|
public var rightItemView: GlassControlGroupComponent.View? {
|
|
return self.rightItemComponent?.view as? GlassControlGroupComponent.View
|
|
}
|
|
|
|
override public init(frame: CGRect) {
|
|
self.glassContainerView = GlassBackgroundContainerView()
|
|
|
|
super.init(frame: frame)
|
|
|
|
self.addSubview(self.glassContainerView)
|
|
}
|
|
|
|
required public init(coder aDecoder: NSCoder) {
|
|
fatalError("init(coder:) has not been implemented")
|
|
}
|
|
|
|
func update(component: GlassControlPanelComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
|
|
self.component = component
|
|
self.state = state
|
|
|
|
let alphaTransition: ComponentTransition = transition.animation.isImmediate ? .immediate : .easeInOut(duration: 0.2)
|
|
let minSpacing: CGFloat = 8.0
|
|
|
|
var leftItemFrame: CGRect?
|
|
if let leftItem = component.leftItem {
|
|
let leftItemComponent: ComponentView<Empty>
|
|
var leftItemTransition = transition
|
|
if let current = self.leftItemComponent {
|
|
leftItemComponent = current
|
|
} else {
|
|
leftItemComponent = ComponentView()
|
|
self.leftItemComponent = leftItemComponent
|
|
leftItemTransition = transition.withAnimation(.none)
|
|
}
|
|
|
|
let leftItemSize = leftItemComponent.update(
|
|
transition: leftItemTransition,
|
|
component: AnyComponent(GlassControlGroupComponent(
|
|
theme: component.theme,
|
|
background: leftItem.background,
|
|
items: leftItem.items,
|
|
minWidth: 40.0
|
|
)),
|
|
environment: {},
|
|
containerSize: CGSize(width: availableSize.width, height: availableSize.height)
|
|
)
|
|
let leftItemFrameValue = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: leftItemSize)
|
|
leftItemFrame = leftItemFrameValue
|
|
if let leftItemComponentView = leftItemComponent.view {
|
|
var animateIn = false
|
|
if leftItemComponentView.superview == nil {
|
|
animateIn = true
|
|
self.glassContainerView.contentView.addSubview(leftItemComponentView)
|
|
ComponentTransition.immediate.setScale(view: leftItemComponentView, scale: 0.001)
|
|
}
|
|
leftItemTransition.setPosition(view: leftItemComponentView, position: leftItemFrameValue.center)
|
|
leftItemTransition.setBounds(view: leftItemComponentView, bounds: CGRect(origin: CGPoint(), size: leftItemFrameValue.size))
|
|
if animateIn {
|
|
alphaTransition.animateAlpha(view: leftItemComponentView, from: 0.0, to: 1.0)
|
|
transition.setScale(view: leftItemComponentView, scale: 1.0)
|
|
}
|
|
}
|
|
} else if let leftItemComponent = self.leftItemComponent {
|
|
self.leftItemComponent = nil
|
|
if let leftItemComponentView = leftItemComponent.view {
|
|
transition.setScale(view: leftItemComponentView, scale: 0.001)
|
|
alphaTransition.setAlpha(view: leftItemComponentView, alpha: 0.0, completion: { [weak leftItemComponentView] _ in
|
|
leftItemComponentView?.removeFromSuperview()
|
|
})
|
|
}
|
|
}
|
|
|
|
var rightItemFrame: CGRect?
|
|
if let rightItem = component.rightItem {
|
|
let rightItemComponent: ComponentView<Empty>
|
|
var rightItemTransition = transition
|
|
if let current = self.rightItemComponent {
|
|
rightItemComponent = current
|
|
} else {
|
|
rightItemComponent = ComponentView()
|
|
self.rightItemComponent = rightItemComponent
|
|
rightItemTransition = transition.withAnimation(.none)
|
|
}
|
|
|
|
let rightItemSize = rightItemComponent.update(
|
|
transition: rightItemTransition,
|
|
component: AnyComponent(GlassControlGroupComponent(
|
|
theme: component.theme,
|
|
background: rightItem.background,
|
|
items: rightItem.items,
|
|
minWidth: 40.0
|
|
)),
|
|
environment: {},
|
|
containerSize: CGSize(width: availableSize.width, height: availableSize.height)
|
|
)
|
|
let rightItemFrameValue = CGRect(origin: CGPoint(x: availableSize.width - rightItemSize.width, y: 0.0), size: rightItemSize)
|
|
rightItemFrame = rightItemFrameValue
|
|
if let rightItemComponentView = rightItemComponent.view {
|
|
var animateIn = false
|
|
if rightItemComponentView.superview == nil {
|
|
animateIn = true
|
|
self.glassContainerView.contentView.addSubview(rightItemComponentView)
|
|
ComponentTransition.immediate.setScale(view: rightItemComponentView, scale: 0.001)
|
|
}
|
|
rightItemTransition.setPosition(view: rightItemComponentView, position: rightItemFrameValue.center)
|
|
rightItemTransition.setBounds(view: rightItemComponentView, bounds: CGRect(origin: CGPoint(), size: rightItemFrameValue.size))
|
|
if animateIn {
|
|
alphaTransition.animateAlpha(view: rightItemComponentView, from: 0.0, to: 1.0)
|
|
transition.setScale(view: rightItemComponentView, scale: 1.0)
|
|
}
|
|
}
|
|
} else if let rightItemComponent = self.rightItemComponent {
|
|
self.rightItemComponent = nil
|
|
if let rightItemComponentView = rightItemComponent.view {
|
|
transition.setScale(view: rightItemComponentView, scale: 0.001)
|
|
alphaTransition.setAlpha(view: rightItemComponentView, alpha: 0.0, completion: { [weak rightItemComponentView] _ in
|
|
rightItemComponentView?.removeFromSuperview()
|
|
})
|
|
}
|
|
}
|
|
|
|
if let centralItem = component.centralItem {
|
|
let centralItemComponent: ComponentView<Empty>
|
|
var centralItemTransition = transition
|
|
if let current = self.centralItemComponent {
|
|
centralItemComponent = current
|
|
} else {
|
|
centralItemComponent = ComponentView()
|
|
self.centralItemComponent = centralItemComponent
|
|
centralItemTransition = transition.withAnimation(.none)
|
|
}
|
|
|
|
var maxCentralItemSize = CGSize(width: availableSize.width, height: availableSize.height)
|
|
var centralRightInset: CGFloat = 0.0
|
|
if let rightItemFrame {
|
|
centralRightInset = availableSize.width - rightItemFrame.minX + minSpacing
|
|
}
|
|
var centralLeftInset: CGFloat = 0.0
|
|
if let leftItemFrame {
|
|
centralLeftInset = leftItemFrame.maxX + minSpacing
|
|
}
|
|
|
|
if centralRightInset <= 48.0 && centralLeftInset <= 48.0 {
|
|
let maxInset = max(centralRightInset, centralLeftInset)
|
|
centralLeftInset = maxInset
|
|
centralRightInset = maxInset
|
|
}
|
|
|
|
maxCentralItemSize.width = max(1.0, availableSize.width - centralLeftInset - centralRightInset)
|
|
|
|
let centralItemSize = centralItemComponent.update(
|
|
transition: centralItemTransition,
|
|
component: AnyComponent(GlassControlGroupComponent(
|
|
theme: component.theme,
|
|
background: centralItem.background,
|
|
items: centralItem.items,
|
|
minWidth: 165.0
|
|
)),
|
|
environment: {},
|
|
containerSize: maxCentralItemSize
|
|
)
|
|
let centralItemFrameValue = CGRect(origin: CGPoint(x: centralLeftInset + floor((availableSize.width - centralLeftInset - centralRightInset - centralItemSize.width) * 0.5), y: 0.0), size: centralItemSize)
|
|
if let centralItemComponentView = centralItemComponent.view {
|
|
var animateIn = false
|
|
if centralItemComponentView.superview == nil {
|
|
animateIn = true
|
|
self.glassContainerView.contentView.addSubview(centralItemComponentView)
|
|
ComponentTransition.immediate.setScale(view: centralItemComponentView, scale: 0.001)
|
|
}
|
|
centralItemTransition.setPosition(view: centralItemComponentView, position: centralItemFrameValue.center)
|
|
centralItemTransition.setBounds(view: centralItemComponentView, bounds: CGRect(origin: CGPoint(), size: centralItemFrameValue.size))
|
|
if animateIn {
|
|
alphaTransition.animateAlpha(view: centralItemComponentView, from: 0.0, to: 1.0)
|
|
transition.setScale(view: centralItemComponentView, scale: 1.0)
|
|
}
|
|
}
|
|
} else if let centralItemComponent = self.centralItemComponent {
|
|
self.centralItemComponent = nil
|
|
if let centralItemComponentView = centralItemComponent.view {
|
|
transition.setScale(view: centralItemComponentView, scale: 0.001)
|
|
alphaTransition.setAlpha(view: centralItemComponentView, alpha: 0.0, completion: { [weak centralItemComponentView] _ in
|
|
centralItemComponentView?.removeFromSuperview()
|
|
})
|
|
}
|
|
}
|
|
|
|
transition.setFrame(view: self.glassContainerView, frame: CGRect(origin: CGPoint(), size: availableSize))
|
|
self.glassContainerView.update(size: availableSize, isDark: component.theme.overallDarkAppearance, transition: transition)
|
|
|
|
return availableSize
|
|
}
|
|
}
|
|
|
|
public func makeView() -> View {
|
|
return View(frame: CGRect())
|
|
}
|
|
|
|
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
|
|
return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition)
|
|
}
|
|
}
|