2023-05-12 21:14:19 +04:00

372 lines
15 KiB
Swift

import Foundation
import UIKit
import Display
import ComponentFlow
import LegacyComponents
import MediaEditor
private final class TintColorComponent: Component {
typealias EnvironmentType = Empty
let color: UIColor
let isSelected: Bool
init(
color: UIColor,
isSelected: Bool
) {
self.color = color
self.isSelected = isSelected
}
static func ==(lhs: TintColorComponent, rhs: TintColorComponent) -> Bool {
if lhs.color != rhs.color {
return false
}
if lhs.isSelected != rhs.isSelected {
return false
}
return true
}
final class View: UIView {
private var background = SimpleShapeLayer()
private var selection = SimpleShapeLayer()
private var component: TintColorComponent?
private weak var state: EmptyComponentState?
private let size = CGSize(width: 24.0, height: 24.0)
override init(frame: CGRect) {
super.init(frame: frame)
self.background.path = CGPath(ellipseIn: CGRect(origin: .zero, size: size).insetBy(dx: 3.0, dy: 3.0), transform: nil)
let lineWidth = 1.0 + UIScreenPixel
self.selection.lineWidth = lineWidth
self.selection.path = CGPath(ellipseIn: CGRect(origin: .zero, size: size).insetBy(dx: lineWidth / 2.0, dy: lineWidth / 2.0), transform: nil)
self.layer.addSublayer(self.selection)
self.layer.addSublayer(self.background)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func update(component: TintColorComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<EnvironmentType>, transition: Transition) -> CGSize {
self.component = component
self.state = state
let size = CGSize(width: 24.0, height: 24.0)
let bounds = CGRect(origin: .zero, size: size)
let color: UIColor
let selectionColor: UIColor
if component.color == .clear {
if component.isSelected {
color = UIColor(rgb: 0x000000)
} else {
color = UIColor(rgb: 0x1c1f22)
}
selectionColor = UIColor(rgb: 0x808080)
} else {
color = component.color
selectionColor = component.color
}
self.background.fillColor = color.cgColor
self.selection.strokeColor = selectionColor.cgColor
self.selection.fillColor = UIColor.clear.cgColor
self.background.frame = bounds
self.selection.frame = bounds
self.selection.isHidden = !component.isSelected
return size
}
}
public func makeView() -> View {
return View(frame: CGRect())
}
public func update(view: View, availableSize: CGSize, state: State, environment: Environment<EnvironmentType>, transition: Transition) -> CGSize {
return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition)
}
}
final class TintComponent: Component {
enum Section {
case shadows
case highlights
}
typealias EnvironmentType = Empty
let shadowsValue: TintValue
let highlightsValue: TintValue
let shadowsValueUpdated: (TintValue) -> Void
let highlightsValueUpdated: (TintValue) -> Void
init(
shadowsValue: TintValue,
highlightsValue: TintValue,
shadowsValueUpdated: @escaping (TintValue) -> Void,
highlightsValueUpdated: @escaping (TintValue) -> Void
) {
self.shadowsValue = shadowsValue
self.highlightsValue = highlightsValue
self.shadowsValueUpdated = shadowsValueUpdated
self.highlightsValueUpdated = highlightsValueUpdated
}
static func ==(lhs: TintComponent, rhs: TintComponent) -> Bool {
if lhs.highlightsValue != rhs.highlightsValue {
return false
}
if lhs.shadowsValue != rhs.shadowsValue {
return false
}
return true
}
final class State: ComponentState {
var section: Section
var shadowsValue: TintValue
var highlightsValue: TintValue
init(section: Section, shadowsValue: TintValue, highlightsValue: TintValue) {
self.section = section
self.shadowsValue = shadowsValue
self.highlightsValue = highlightsValue
}
}
func makeState() -> State {
return State(section: .shadows, shadowsValue: self.shadowsValue, highlightsValue: self.highlightsValue)
}
final class View: UIView {
private var shadowsButton = ComponentView<Empty>()
private var highlightsButton = ComponentView<Empty>()
private var colorViews: [ComponentView<Empty>] = []
private var slider = ComponentView<Empty>()
private var component: TintComponent?
private weak var state: State?
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func update(component: TintComponent, availableSize: CGSize, state: State, environment: Environment<EnvironmentType>, transition: Transition) -> CGSize {
self.component = component
self.state = state
state.shadowsValue = component.shadowsValue
state.highlightsValue = component.highlightsValue
let shadowsValueUpdated = component.shadowsValueUpdated
let highlightsValueUpdated = component.highlightsValueUpdated
let topInset: CGFloat = 11.0
let shadowsButtonSize = self.shadowsButton.update(
transition: transition,
component: AnyComponent(
Button(
content: AnyComponent(
Text(
text: "Shadows",
font: Font.regular(14.0),
color: state.section == .shadows ? .white : UIColor(rgb: 0x808080)
)
),
action: { [weak state] in
state?.section = .shadows
state?.updated()
}
)
),
environment: {},
containerSize: availableSize
)
let shadowsButtonFrame = CGRect(origin: CGPoint(x: floorToScreenPixels(availableSize.width / 3.0 - shadowsButtonSize.width / 2.0), y: topInset), size: shadowsButtonSize)
if let view = self.shadowsButton.view {
if view.superview == nil {
self.addSubview(view)
}
transition.setFrame(view: view, frame: shadowsButtonFrame)
}
let highlightsButtonSize = self.highlightsButton.update(
transition: transition,
component: AnyComponent(
Button(
content: AnyComponent(
Text(
text: "Highlights",
font: Font.regular(14.0),
color: state.section == .highlights ? .white : UIColor(rgb: 0x808080)
)
),
action: { [weak state] in
state?.section = .highlights
state?.updated()
}
)
),
environment: {},
containerSize: availableSize
)
let highlightsButtonFrame = CGRect(origin: CGPoint(x: floorToScreenPixels(availableSize.width / 3.0 * 2.0 - highlightsButtonSize.width / 2.0), y: topInset), size: highlightsButtonSize)
if let view = self.highlightsButton.view {
if view.superview == nil {
self.addSubview(view)
}
transition.setFrame(view: view, frame: highlightsButtonFrame)
}
let currentColor: UIColor
let colors: [UIColor]
switch state.section {
case .shadows:
currentColor = component.shadowsValue.color
colors = [
UIColor.clear,
UIColor(rgb: 0xff4d4d),
UIColor(rgb: 0xf48022),
UIColor(rgb: 0xffcd00),
UIColor(rgb: 0x81d281),
UIColor(rgb: 0x71c5d6),
UIColor(rgb: 0x0072bc),
UIColor(rgb: 0x662d91)
]
case .highlights:
currentColor = component.highlightsValue.color
colors = [
UIColor.clear,
UIColor(rgb: 0xef9286),
UIColor(rgb: 0xeacea2),
UIColor(rgb: 0xf2e17c),
UIColor(rgb: 0xa4edae),
UIColor(rgb: 0x89dce5),
UIColor(rgb: 0x2e8bc8),
UIColor(rgb: 0xcd98e5)
]
}
var sizes: [CGSize] = []
for i in 0 ..< colors.count {
let color = colors[i]
let componentView: ComponentView<Empty>
if i >= self.colorViews.count {
componentView = ComponentView<Empty>()
self.colorViews.append(componentView)
} else {
componentView = self.colorViews[i]
}
let size = componentView.update(
transition: transition,
component: AnyComponent(
Button(
content: AnyComponent(
TintColorComponent(
color: color,
isSelected: color == currentColor
)
),
action: { [weak state] in
if let state {
switch state.section {
case .shadows:
shadowsValueUpdated(state.shadowsValue.withUpdatedColor(color))
case .highlights:
highlightsValueUpdated(state.highlightsValue.withUpdatedColor(color))
}
}
}
)
),
environment: {},
containerSize: availableSize
)
sizes.append(size)
}
let sliderSize = self.slider.update(
transition: transition,
component: AnyComponent(
AdjustmentSliderComponent(
title: "",
value: state.section == .shadows ? component.shadowsValue.intensity : component.highlightsValue.intensity,
minValue: 0.0,
maxValue: 1.0,
startValue: 0.0,
isEnabled: currentColor != .clear,
trackColor: currentColor != .clear ? currentColor : .white,
displayValue: false,
valueUpdated: { [weak state] value in
if let state {
switch state.section {
case .shadows:
shadowsValueUpdated(state.shadowsValue.withUpdatedIntensity(value))
case .highlights:
highlightsValueUpdated(state.highlightsValue.withUpdatedIntensity(value))
}
}
}
)
),
environment: {},
containerSize: availableSize
)
let colorsVerticalSpacing: CGFloat = 9.0
let leftInset: CGFloat = 30.0
let itemSpacing = min(33.0, floorToScreenPixels((availableSize.width - leftInset * 2.0 - sizes.first!.width * CGFloat(colors.count)) / CGFloat(colors.count - 1)))
let finalLeftInset: CGFloat = floorToScreenPixels((availableSize.width - ((sizes.first!.width + itemSpacing) * CGFloat(colors.count) - itemSpacing)) / 2.0)
var origin: CGPoint = CGPoint(x: finalLeftInset, y: topInset + highlightsButtonSize.height + colorsVerticalSpacing)
for i in 0 ..< colors.count {
let size = sizes[i]
let componentView = self.colorViews[i]
if let view = componentView.view {
if view.superview == nil {
self.addSubview(view)
}
transition.setFrame(view: view, frame: CGRect(origin: origin, size: size))
}
origin = origin.offsetBy(dx: size.width + itemSpacing, dy: 0.0)
}
let verticalSpacing: CGFloat = 3.0
let sliderFrame = CGRect(origin: CGPoint(x: 0.0, y: topInset + highlightsButtonSize.height + verticalSpacing + sizes.first!.height + verticalSpacing), size: sliderSize)
if let view = self.slider.view {
if view.superview == nil {
self.addSubview(view)
}
transition.setFrame(view: view, frame: sliderFrame)
}
return CGSize(width: availableSize.width, height: topInset + highlightsButtonSize.height + colorsVerticalSpacing + sizes.first!.height + verticalSpacing + sliderSize.height)
}
}
public func makeView() -> View {
return View(frame: CGRect())
}
public func update(view: View, availableSize: CGSize, state: State, environment: Environment<EnvironmentType>, transition: Transition) -> CGSize {
return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition)
}
}