mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
372 lines
15 KiB
Swift
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)
|
|
}
|
|
}
|
|
|