mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-22 22:25:57 +00:00
Drawing
This commit is contained in:
@@ -3,15 +3,18 @@ import UIKit
|
||||
import Display
|
||||
import ComponentFlow
|
||||
import ViewControllerComponent
|
||||
import SwiftSignalKit
|
||||
|
||||
public final class SheetComponentEnvironment: Equatable {
|
||||
public let isDisplaying: Bool
|
||||
public let isCentered: Bool
|
||||
public let hasInputHeight: Bool
|
||||
public let dismiss: (Bool) -> Void
|
||||
|
||||
public init(isDisplaying: Bool, isCentered: Bool, dismiss: @escaping (Bool) -> Void) {
|
||||
public init(isDisplaying: Bool, isCentered: Bool, hasInputHeight: Bool, dismiss: @escaping (Bool) -> Void) {
|
||||
self.isDisplaying = isDisplaying
|
||||
self.isCentered = isCentered
|
||||
self.hasInputHeight = hasInputHeight
|
||||
self.dismiss = dismiss
|
||||
}
|
||||
|
||||
@@ -22,6 +25,9 @@ public final class SheetComponentEnvironment: Equatable {
|
||||
if lhs.isCentered != rhs.isCentered {
|
||||
return false
|
||||
}
|
||||
if lhs.hasInputHeight != rhs.hasInputHeight {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -29,11 +35,21 @@ public final class SheetComponentEnvironment: Equatable {
|
||||
public final class SheetComponent<ChildEnvironmentType: Equatable>: Component {
|
||||
public typealias EnvironmentType = (ChildEnvironmentType, SheetComponentEnvironment)
|
||||
|
||||
public enum BackgroundColor: Equatable {
|
||||
public enum BlurStyle: Equatable {
|
||||
case light
|
||||
case dark
|
||||
}
|
||||
|
||||
case color(UIColor)
|
||||
case blur(BlurStyle)
|
||||
}
|
||||
|
||||
public let content: AnyComponent<ChildEnvironmentType>
|
||||
public let backgroundColor: UIColor
|
||||
public let backgroundColor: BackgroundColor
|
||||
public let animateOut: ActionSlot<Action<()>>
|
||||
|
||||
public init(content: AnyComponent<ChildEnvironmentType>, backgroundColor: UIColor, animateOut: ActionSlot<Action<()>>) {
|
||||
public init(content: AnyComponent<ChildEnvironmentType>, backgroundColor: BackgroundColor, animateOut: ActionSlot<Action<()>>) {
|
||||
self.content = content
|
||||
self.backgroundColor = backgroundColor
|
||||
self.animateOut = animateOut
|
||||
@@ -53,20 +69,36 @@ public final class SheetComponent<ChildEnvironmentType: Equatable>: Component {
|
||||
return true
|
||||
}
|
||||
|
||||
private class ScrollView: UIScrollView {
|
||||
var ignoreScroll = false
|
||||
override func setContentOffset(_ contentOffset: CGPoint, animated: Bool) {
|
||||
guard !self.ignoreScroll else {
|
||||
return
|
||||
}
|
||||
if animated && abs(contentOffset.y - self.contentOffset.y) > 200.0 {
|
||||
return
|
||||
}
|
||||
super.setContentOffset(contentOffset, animated: animated)
|
||||
}
|
||||
}
|
||||
|
||||
public final class View: UIView, UIScrollViewDelegate {
|
||||
private let dimView: UIView
|
||||
private let scrollView: UIScrollView
|
||||
private let scrollView: ScrollView
|
||||
private let backgroundView: UIView
|
||||
private var effectView: UIVisualEffectView?
|
||||
private let contentView: ComponentHostView<ChildEnvironmentType>
|
||||
|
||||
private var previousIsDisplaying: Bool = false
|
||||
private var dismiss: ((Bool) -> Void)?
|
||||
|
||||
private var keyboardWillShowObserver: AnyObject?
|
||||
|
||||
override init(frame: CGRect) {
|
||||
self.dimView = UIView()
|
||||
self.dimView.backgroundColor = UIColor(white: 0.0, alpha: 0.4)
|
||||
|
||||
self.scrollView = UIScrollView()
|
||||
self.scrollView = ScrollView()
|
||||
self.scrollView.delaysContentTouches = false
|
||||
if #available(iOSApplicationExtension 11.0, iOS 11.0, *) {
|
||||
self.scrollView.contentInsetAdjustmentBehavior = .never
|
||||
@@ -76,7 +108,7 @@ public final class SheetComponent<ChildEnvironmentType: Equatable>: Component {
|
||||
self.scrollView.alwaysBounceVertical = true
|
||||
|
||||
self.backgroundView = UIView()
|
||||
self.backgroundView.layer.cornerRadius = 10.0
|
||||
self.backgroundView.layer.cornerRadius = 12.0
|
||||
self.backgroundView.layer.masksToBounds = true
|
||||
|
||||
self.contentView = ComponentHostView<ChildEnvironmentType>()
|
||||
@@ -91,12 +123,27 @@ public final class SheetComponent<ChildEnvironmentType: Equatable>: Component {
|
||||
self.addSubview(self.scrollView)
|
||||
|
||||
self.dimView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.dimViewTapGesture(_:))))
|
||||
|
||||
self.keyboardWillShowObserver = NotificationCenter.default.addObserver(forName: UIResponder.keyboardWillShowNotification, object: nil, queue: nil, using: { [weak self] _ in
|
||||
if let strongSelf = self {
|
||||
strongSelf.scrollView.ignoreScroll = true
|
||||
Queue.mainQueue().after(0.1, {
|
||||
strongSelf.scrollView.ignoreScroll = false
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
deinit {
|
||||
if let keyboardFrameChangeObserver = self.keyboardWillShowObserver {
|
||||
NotificationCenter.default.removeObserver(keyboardFrameChangeObserver)
|
||||
}
|
||||
}
|
||||
|
||||
@objc private func dimViewTapGesture(_ recognizer: UITapGestureRecognizer) {
|
||||
if case .ended = recognizer.state {
|
||||
self.dismiss?(true)
|
||||
@@ -183,8 +230,10 @@ public final class SheetComponent<ChildEnvironmentType: Equatable>: Component {
|
||||
}
|
||||
}
|
||||
|
||||
private var currentHasInputHeight = false
|
||||
private var currentAvailableSize: CGSize?
|
||||
func update(component: SheetComponent<ChildEnvironmentType>, availableSize: CGSize, state: EmptyComponentState, environment: Environment<EnvironmentType>, transition: Transition) -> CGSize {
|
||||
let previousHasInputHeight = self.currentHasInputHeight
|
||||
let sheetEnvironment = environment[SheetComponentEnvironment.self].value
|
||||
component.animateOut.connect { [weak self] completion in
|
||||
guard let strongSelf = self else {
|
||||
@@ -195,10 +244,25 @@ public final class SheetComponent<ChildEnvironmentType: Equatable>: Component {
|
||||
}
|
||||
}
|
||||
|
||||
if self.backgroundView.backgroundColor != component.backgroundColor {
|
||||
self.backgroundView.backgroundColor = component.backgroundColor
|
||||
}
|
||||
self.currentHasInputHeight = sheetEnvironment.hasInputHeight
|
||||
|
||||
switch component.backgroundColor {
|
||||
case let .blur(style):
|
||||
self.backgroundView.isHidden = true
|
||||
if self.effectView == nil {
|
||||
let effectView = UIVisualEffectView(effect: UIBlurEffect(style: style == .dark ? .dark : .light))
|
||||
effectView.layer.cornerRadius = self.backgroundView.layer.cornerRadius
|
||||
effectView.layer.masksToBounds = true
|
||||
self.backgroundView.superview?.insertSubview(effectView, aboveSubview: self.backgroundView)
|
||||
self.effectView = effectView
|
||||
}
|
||||
case let .color(color):
|
||||
self.backgroundView.backgroundColor = color
|
||||
self.backgroundView.isHidden = false
|
||||
self.effectView?.removeFromSuperview()
|
||||
self.effectView = nil
|
||||
}
|
||||
|
||||
transition.setFrame(view: self.dimView, frame: CGRect(origin: CGPoint(), size: availableSize), completion: nil)
|
||||
|
||||
let containerSize: CGSize
|
||||
@@ -226,9 +290,15 @@ public final class SheetComponent<ChildEnvironmentType: Equatable>: Component {
|
||||
let y: CGFloat = floorToScreenPixels((availableSize.height - contentSize.height) / 2.0)
|
||||
transition.setFrame(view: self.contentView, frame: CGRect(origin: CGPoint(x: floorToScreenPixels((availableSize.width - contentSize.width) / 2.0), y: -y), size: contentSize), completion: nil)
|
||||
transition.setFrame(view: self.backgroundView, frame: CGRect(origin: CGPoint(x: floorToScreenPixels((availableSize.width - contentSize.width) / 2.0), y: -y), size: contentSize), completion: nil)
|
||||
if let effectView = self.effectView {
|
||||
transition.setFrame(view: effectView, frame: CGRect(origin: CGPoint(x: floorToScreenPixels((availableSize.width - contentSize.width) / 2.0), y: -y), size: contentSize), completion: nil)
|
||||
}
|
||||
} else {
|
||||
transition.setFrame(view: self.contentView, frame: CGRect(origin: .zero, size: contentSize), completion: nil)
|
||||
transition.setFrame(view: self.backgroundView, frame: CGRect(origin: .zero, size: CGSize(width: contentSize.width, height: contentSize.height + 1000.0)), completion: nil)
|
||||
if let effectView = self.effectView {
|
||||
transition.setFrame(view: effectView, frame: CGRect(origin: .zero, size: CGSize(width: contentSize.width, height: contentSize.height + 1000.0)), completion: nil)
|
||||
}
|
||||
}
|
||||
transition.setFrame(view: self.scrollView, frame: CGRect(origin: CGPoint(), size: availableSize), completion: nil)
|
||||
|
||||
@@ -239,6 +309,10 @@ public final class SheetComponent<ChildEnvironmentType: Equatable>: Component {
|
||||
if let currentAvailableSize = self.currentAvailableSize, currentAvailableSize.height != availableSize.height {
|
||||
self.scrollView.contentOffset = CGPoint(x: 0.0, y: -(availableSize.height - contentSize.height))
|
||||
}
|
||||
if self.currentHasInputHeight != previousHasInputHeight {
|
||||
transition.setBounds(view: self.scrollView, bounds: CGRect(origin: CGPoint(x: 0.0, y: -(availableSize.height - contentSize.height)), size: self.scrollView.bounds.size))
|
||||
}
|
||||
|
||||
self.currentAvailableSize = availableSize
|
||||
|
||||
if environment[SheetComponentEnvironment.self].value.isDisplaying, !self.previousIsDisplaying, let _ = transition.userData(ViewControllerComponentContainer.AnimateInTransition.self) {
|
||||
|
||||
Reference in New Issue
Block a user