import Foundation import UIKit import Display import ComponentFlow import LegacyComponents import MediaEditor final class AdjustmentSliderComponent: Component { typealias EnvironmentType = Empty let title: String let value: Float let minValue: Float let maxValue: Float let startValue: Float let isEnabled: Bool let trackColor: UIColor? let updateValue: (Float) -> Void init( title: String, value: Float, minValue: Float, maxValue: Float, startValue: Float, isEnabled: Bool, trackColor: UIColor?, updateValue: @escaping (Float) -> Void ) { self.title = title self.value = value self.minValue = minValue self.maxValue = maxValue self.startValue = startValue self.isEnabled = isEnabled self.trackColor = trackColor self.updateValue = updateValue } static func ==(lhs: AdjustmentSliderComponent, rhs: AdjustmentSliderComponent) -> Bool { if lhs.title != rhs.title { return false } if lhs.value != rhs.value { return false } if lhs.minValue != rhs.minValue { return false } if lhs.maxValue != rhs.maxValue { return false } if lhs.startValue != rhs.startValue { return false } if lhs.isEnabled != rhs.isEnabled { return false } if lhs.trackColor != rhs.trackColor { return false } return true } final class View: UIView, UITextFieldDelegate { private let title = ComponentView() private let value = ComponentView() private var sliderView: TGPhotoEditorSliderView? private var component: AdjustmentSliderComponent? private weak var state: EmptyComponentState? override init(frame: CGRect) { super.init(frame: frame) } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } func update(component: AdjustmentSliderComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment, transition: Transition) -> CGSize { self.component = component self.state = state let sliderView: TGPhotoEditorSliderView if let current = self.sliderView { sliderView = current sliderView.value = CGFloat(component.value) } else { sliderView = TGPhotoEditorSliderView() sliderView.backgroundColor = .clear sliderView.enablePanHandling = true sliderView.trackCornerRadius = 1.0 sliderView.lineSize = 2.0 sliderView.minimumValue = CGFloat(component.minValue) sliderView.maximumValue = CGFloat(component.maxValue) sliderView.startValue = CGFloat(component.startValue) sliderView.value = CGFloat(component.value) sliderView.disablesInteractiveTransitionGestureRecognizer = true sliderView.addTarget(self, action: #selector(self.sliderValueChanged), for: .valueChanged) sliderView.layer.allowsGroupOpacity = true self.sliderView = sliderView self.addSubview(sliderView) } if component.isEnabled { sliderView.alpha = 1.3 sliderView.trackColor = component.trackColor ?? UIColor(rgb: 0xffffff) sliderView.isUserInteractionEnabled = true } else { sliderView.trackColor = UIColor(rgb: 0xffffff) sliderView.alpha = 0.3 sliderView.isUserInteractionEnabled = false } transition.setFrame(view: sliderView, frame: CGRect(origin: CGPoint(x: 22.0, y: 7.0), size: CGSize(width: availableSize.width - 22.0 * 2.0, height: 44.0))) sliderView.hitTestEdgeInsets = UIEdgeInsets(top: -sliderView.frame.minX, left: 0.0, bottom: 0.0, right: -sliderView.frame.minX) let titleSize = self.title.update( transition: .immediate, component: AnyComponent( Text(text: component.title, font: Font.regular(14.0), color: UIColor(rgb: 0x808080)) ), environment: {}, containerSize: CGSize(width: 100.0, height: 100.0) ) if let titleView = self.title.view { if titleView.superview == nil { self.addSubview(titleView) } transition.setFrame(view: titleView, frame: CGRect(origin: CGPoint(x: 21.0, y: 0.0), size: titleSize)) } return CGSize(width: availableSize.width, height: 52.0) } @objc private func sliderValueChanged() { guard let component = self.component, let sliderView = self.sliderView else { return } component.updateValue(Float(sliderView.value)) } } public func makeView() -> View { return View(frame: CGRect()) } public func update(view: View, availableSize: CGSize, state: State, environment: Environment, transition: Transition) -> CGSize { return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition) } } struct AdjustmentTool: Equatable { let key: EditorToolKey let title: String let value: Float let minValue: Float let maxValue: Float let startValue: Float } final class AdjustmentsComponent: Component { typealias EnvironmentType = Empty let tools: [AdjustmentTool] let valueUpdated: (EditorToolKey, Float) -> Void init( tools: [AdjustmentTool], valueUpdated: @escaping (EditorToolKey, Float) -> Void ) { self.tools = tools self.valueUpdated = valueUpdated } static func ==(lhs: AdjustmentsComponent, rhs: AdjustmentsComponent) -> Bool { if lhs.tools != rhs.tools { return false } return true } final class View: UIView { private let scrollView = UIScrollView() private var toolViews: [ComponentView] = [] private var component: AdjustmentsComponent? private weak var state: EmptyComponentState? override init(frame: CGRect) { self.scrollView.showsVerticalScrollIndicator = false super.init(frame: frame) self.addSubview(self.scrollView) } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } func update(component: AdjustmentsComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment, transition: Transition) -> CGSize { self.component = component self.state = state let valueUpdated = component.valueUpdated var sizes: [CGSize] = [] for i in 0 ..< component.tools.count { let tool = component.tools[i] let componentView: ComponentView if i >= self.toolViews.count { componentView = ComponentView() self.toolViews.append(componentView) } else { componentView = self.toolViews[i] } let size = componentView.update( transition: transition, component: AnyComponent( AdjustmentSliderComponent( title: tool.title, value: tool.value, minValue: tool.minValue, maxValue: tool.maxValue, startValue: tool.startValue, isEnabled: true, trackColor: nil, updateValue: { value in valueUpdated(tool.key, value) } ) ), environment: {}, containerSize: availableSize ) sizes.append(size) } var origin: CGPoint = CGPoint(x: 0.0, y: 11.0) for i in 0 ..< component.tools.count { let size = sizes[i] let componentView = self.toolViews[i] if let view = componentView.view { if view.superview == nil { self.scrollView.addSubview(view) } transition.setFrame(view: view, frame: CGRect(origin: origin, size: size)) } origin = origin.offsetBy(dx: 0.0, dy: size.height) } let size = CGSize(width: availableSize.width, height: 180.0) let contentSize = CGSize(width: availableSize.width, height: origin.y) if contentSize != self.scrollView.contentSize { self.scrollView.contentSize = contentSize } transition.setFrame(view: self.scrollView, frame: CGRect(origin: .zero, size: size)) return size } } public func makeView() -> View { return View(frame: CGRect()) } public func update(view: View, availableSize: CGSize, state: State, environment: Environment, transition: Transition) -> CGSize { return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition) } }