Stream improvements

This commit is contained in:
Ali
2022-02-26 02:22:10 +04:00
parent 6fb5008c0f
commit 089642a0bb
35 changed files with 1227 additions and 309 deletions

View File

@@ -17,7 +17,7 @@ private func findTaggedViewImpl(view: UIView, tag: Any) -> UIView? {
return nil
}
public final class ComponentHostView<EnvironmentType>: UIView {
public final class ComponentHostView<EnvironmentType: Equatable>: UIView {
private var currentComponent: AnyComponent<EnvironmentType>?
private var currentContainerSize: CGSize?
private var currentSize: CGSize?
@@ -33,19 +33,12 @@ public final class ComponentHostView<EnvironmentType>: UIView {
}
public func update(transition: Transition, component: AnyComponent<EnvironmentType>, @EnvironmentBuilder environment: () -> Environment<EnvironmentType>, containerSize: CGSize) -> CGSize {
if let currentComponent = self.currentComponent, let currentContainerSize = self.currentContainerSize, let currentSize = self.currentSize {
if currentContainerSize == containerSize && currentComponent == component {
return currentSize
}
}
self.currentComponent = component
self.currentContainerSize = containerSize
let size = self._update(transition: transition, component: component, maybeEnvironment: environment, updateEnvironment: true, containerSize: containerSize)
let size = self._update(transition: transition, component: component, maybeEnvironment: environment, updateEnvironment: true, forceUpdate: false, containerSize: containerSize)
self.currentSize = size
return size
}
private func _update(transition: Transition, component: AnyComponent<EnvironmentType>, maybeEnvironment: () -> Environment<EnvironmentType>, updateEnvironment: Bool, containerSize: CGSize) -> CGSize {
private func _update(transition: Transition, component: AnyComponent<EnvironmentType>, maybeEnvironment: () -> Environment<EnvironmentType>, updateEnvironment: Bool, forceUpdate: Bool, containerSize: CGSize) -> CGSize {
precondition(!self.isUpdating)
self.isUpdating = true
@@ -72,6 +65,20 @@ public final class ComponentHostView<EnvironmentType>: UIView {
let _ = maybeEnvironment()
EnvironmentBuilder._environment = nil
}
let isEnvironmentUpdated = context.erasedEnvironment.calculateIsUpdated()
if isEnvironmentUpdated {
context.erasedEnvironment._isUpdated = false
}
if !forceUpdate, !isEnvironmentUpdated, let currentComponent = self.currentComponent, let currentContainerSize = self.currentContainerSize, let currentSize = self.currentSize {
if currentContainerSize == containerSize && currentComponent == component {
self.isUpdating = false
return currentSize
}
}
self.currentComponent = component
self.currentContainerSize = containerSize
componentState._updated = { [weak self] transition in
guard let strongSelf = self else {
@@ -79,7 +86,7 @@ public final class ComponentHostView<EnvironmentType>: UIView {
}
let _ = strongSelf._update(transition: transition, component: component, maybeEnvironment: {
preconditionFailure()
} as () -> Environment<EnvironmentType>, updateEnvironment: false, containerSize: containerSize)
} as () -> Environment<EnvironmentType>, updateEnvironment: false, forceUpdate: true, containerSize: containerSize)
}
let updatedSize = component._update(view: componentView, availableSize: containerSize, environment: context.erasedEnvironment, transition: transition)

View File

@@ -1,134 +1,3 @@
import Foundation
import UIKit
public final class RootHostView<EnvironmentType: Equatable>: UIViewController {
private let content: AnyComponent<(NavigationLayout, EnvironmentType)>
private var keyboardWillChangeFrameObserver: NSObjectProtocol?
private var inputHeight: CGFloat = 0.0
private let environment: Environment<EnvironmentType>
private var componentView: ComponentHostView<(NavigationLayout, EnvironmentType)>
private var scheduledTransition: Transition?
public init(
content: AnyComponent<(NavigationLayout, EnvironmentType)>,
@EnvironmentBuilder environment: () -> Environment<EnvironmentType>
) {
self.content = content
self.environment = Environment<EnvironmentType>()
self.componentView = ComponentHostView<(NavigationLayout, EnvironmentType)>()
EnvironmentBuilder._environment = self.environment
let _ = environment()
EnvironmentBuilder._environment = nil
super.init(nibName: nil, bundle: nil)
NotificationCenter.default.addObserver(forName: UIApplication.keyboardWillChangeFrameNotification, object: nil, queue: nil, using: { [weak self] notification in
guard let strongSelf = self else {
return
}
guard let keyboardFrame = notification.userInfo?[UIApplication.keyboardFrameEndUserInfoKey] as? CGRect else {
return
}
var duration: Double = (notification.userInfo?[UIResponder.keyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue ?? 0.0
if duration > Double.ulpOfOne {
duration = 0.5
}
let curve: UInt = (notification.userInfo?[UIResponder.keyboardAnimationCurveUserInfoKey] as? NSNumber)?.uintValue ?? 7
let transition: Transition
if curve == 7 {
transition = Transition(animation: .curve(duration: duration, curve: .spring))
} else {
transition = Transition(animation: .curve(duration: duration, curve: .easeInOut))
}
strongSelf.updateKeyboardLayout(keyboardFrame: keyboardFrame, transition: transition)
})
}
required public init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
deinit {
self.keyboardWillChangeFrameObserver.flatMap(NotificationCenter.default.removeObserver)
}
private func updateKeyboardLayout(keyboardFrame: CGRect, transition: Transition) {
self.inputHeight = max(0.0, self.view.bounds.height - keyboardFrame.minY)
if self.componentView.isUpdating || true {
if let _ = self.scheduledTransition {
if case .curve = transition.animation {
self.scheduledTransition = transition
}
} else {
self.scheduledTransition = transition
}
self.view.setNeedsLayout()
} else {
self.updateComponent(size: self.view.bounds.size, transition: transition)
}
}
private func updateComponent(size: CGSize, transition: Transition) {
self.environment._isUpdated = false
transition.setFrame(view: self.componentView, frame: CGRect(origin: CGPoint(), size: size))
let _ = self.componentView.update(
transition: transition,
component: self.content,
environment: {
NavigationLayout(
statusBarHeight: size.width > size.height ? 0.0 : 40.0,
inputHeight: self.inputHeight,
bottomNavigationHeight: 22.0
)
self.environment[EnvironmentType.self]
},
containerSize: size
)
}
public func updateEnvironment(@EnvironmentBuilder environment: () -> Environment<EnvironmentType>) {
EnvironmentBuilder._environment = self.environment
let _ = environment()
EnvironmentBuilder._environment = nil
if self.environment.calculateIsUpdated() {
if !self.view.bounds.size.width.isZero {
self.updateComponent(size: self.view.bounds.size, transition: .immediate)
}
}
}
override public func viewDidLoad() {
super.viewDidLoad()
self.view.addSubview(self.componentView)
if !self.view.bounds.size.width.isZero {
self.updateComponent(size: self.view.bounds.size, transition: .immediate)
}
}
override public func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
if let scheduledTransition = self.scheduledTransition {
self.scheduledTransition = nil
self.updateComponent(size: self.view.bounds.size, transition: scheduledTransition)
}
}
override public func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
self.updateComponent(size: size, transition: coordinator.isAnimated ? .easeInOut(duration: 0.3) : .immediate)
}
}