Swiftgram/TelegramUI/WallpaperColorPanelNode.swift

180 lines
9.1 KiB
Swift

import Foundation
import AsyncDisplayKit
import SwiftSignalKit
import Display
private var currentTextInputBackgroundImage: (UIColor, UIColor, UIColor, CGFloat, UIImage)?
private func textInputBackgroundImage(backgroundColor: UIColor, fieldColor: UIColor, strokeColor: UIColor, diameter: CGFloat) -> UIImage? {
if let current = currentTextInputBackgroundImage {
if current.0.isEqual(backgroundColor) && current.1.isEqual(fieldColor) && current.2.isEqual(strokeColor) && current.3.isEqual(to: diameter) {
return current.4
}
}
let image = generateImage(CGSize(width: diameter, height: diameter), rotatedContext: { size, context in
context.setFillColor(backgroundColor.cgColor)
context.fill(CGRect(x: 0.0, y: 0.0, width: diameter, height: diameter))
context.setFillColor(fieldColor.cgColor)
context.fillEllipse(in: CGRect(x: 0.0, y: 0.0, width: diameter, height: diameter))
context.setStrokeColor(strokeColor.cgColor)
let strokeWidth: CGFloat = 1.0
context.setLineWidth(strokeWidth)
context.strokeEllipse(in: CGRect(x: strokeWidth / 2.0, y: strokeWidth / 2.0, width: diameter - strokeWidth, height: diameter - strokeWidth))
})?.stretchableImage(withLeftCapWidth: Int(diameter) / 2, topCapHeight: Int(diameter) / 2)
if let image = image {
currentTextInputBackgroundImage = (backgroundColor, fieldColor, strokeColor, diameter, image)
return image
} else {
return nil
}
}
final class WallpaperColorPanelNode: ASDisplayNode, UITextFieldDelegate {
private let theme: PresentationTheme
private let backgroundNode: ASDisplayNode
private let topSeparatorNode: ASDisplayNode
private let bottomSeparatorNode: ASDisplayNode
private let textBackgroundNode: ASImageNode
private let textFieldNode: TextFieldNode
private let prefixNode: ASTextNode
private let palleteButton: HighlightableButtonNode
private let doneButton: HighlightableButtonNode
private let colorPickerNode: WallpaperColorPickerNode
var color: UIColor {
get {
return self.colorPickerNode.color
}
set {
self.setColor(newValue)
}
}
var colorChanged: ((UIColor) -> Void)?
init(theme: PresentationTheme) {
self.theme = theme
self.backgroundNode = ASDisplayNode()
self.backgroundNode.backgroundColor = theme.chat.inputPanel.panelBackgroundColor
self.topSeparatorNode = ASDisplayNode()
self.topSeparatorNode.backgroundColor = theme.chat.inputPanel.panelStrokeColor
self.bottomSeparatorNode = ASDisplayNode()
self.bottomSeparatorNode.backgroundColor = theme.chat.inputPanel.panelStrokeColor
self.textBackgroundNode = ASImageNode()
self.textBackgroundNode.image = textInputBackgroundImage(backgroundColor: theme.chat.inputPanel.panelBackgroundColor, fieldColor: theme.chat.inputPanel.inputBackgroundColor, strokeColor: theme.chat.inputPanel.inputStrokeColor, diameter: 33.0)
self.textFieldNode = TextFieldNode()
self.prefixNode = ASTextNode()
self.prefixNode.attributedText = NSAttributedString(string: "#", font: Font.regular(17.0), textColor: self.theme.chat.inputPanel.inputTextColor)
self.palleteButton = HighlightableButtonNode()
self.palleteButton.setImage(generateTintedImage(image: UIImage(bundleImageName: "Settings/WallpaperColorIcon"), color: theme.chat.inputPanel.panelControlColor), for: .normal)
self.doneButton = HighlightableButtonNode()
self.doneButton.setImage(PresentationResourcesChat.chatInputPanelApplyButtonImage(theme), for: .normal)
self.colorPickerNode = WallpaperColorPickerNode()
super.init()
self.addSubnode(self.backgroundNode)
self.addSubnode(self.topSeparatorNode)
self.addSubnode(self.bottomSeparatorNode)
self.addSubnode(self.textBackgroundNode)
self.addSubnode(self.textFieldNode)
self.addSubnode(self.prefixNode)
self.addSubnode(self.doneButton)
self.addSubnode(self.colorPickerNode)
self.colorPickerNode.colorChanged = { [weak self] color in
self?.setColor(color, updatePicker: false)
}
}
override func didLoad() {
super.didLoad()
self.textFieldNode.textField.font = Font.regular(17.0)
self.textFieldNode.textField.textColor = self.theme.chat.inputPanel.inputTextColor
self.textFieldNode.textField.keyboardAppearance = self.theme.chat.inputPanel.keyboardColor.keyboardAppearance
self.textFieldNode.textField.autocorrectionType = .no
self.textFieldNode.textField.autocapitalizationType = .allCharacters
self.textFieldNode.textField.keyboardType = .asciiCapable
self.textFieldNode.textField.returnKeyType = .done
self.textFieldNode.textField.delegate = self
self.textFieldNode.textField.addTarget(self, action: #selector(self.textFieldTextChanged(_:)), for: .editingChanged)
self.textFieldNode.hitTestSlop = UIEdgeInsets(top: -5.0, left: -5.0, bottom: -5.0, right: -5.0)
}
private func setColor(_ color: UIColor, updatePicker: Bool = true) {
self.textFieldNode.textField.text = color.hexString.uppercased()
if updatePicker {
self.colorPickerNode.color = color
}
self.colorChanged?(color)
}
func updateLayout(size: CGSize, keyboardHeight: CGFloat, transition: ContainedViewLayoutTransition) {
let separatorHeight = UIScreenPixel
let topPanelHeight: CGFloat = 47.0
transition.updateFrame(node: self.backgroundNode, frame: CGRect(x: 0.0, y: 0.0, width: size.width, height: topPanelHeight))
transition.updateFrame(node: self.topSeparatorNode, frame: CGRect(x: 0.0, y: 0.0, width: size.width, height: separatorHeight))
transition.updateFrame(node: self.bottomSeparatorNode, frame: CGRect(x: 0.0, y: topPanelHeight, width: size.width, height: separatorHeight))
let fieldHeight: CGFloat = 33.0
let buttonSpacing: CGFloat = keyboardHeight > 0.0 ? 3.0 : 6.0
let leftInset: CGFloat = 5.0 //42.0
let rightInset: CGFloat = 5.0 //keyboardHeight > 0.0 ? 42.0 : 5.0
transition.updateFrame(node: self.palleteButton, frame: CGRect(x: 0.0, y: 0.0, width: topPanelHeight, height: topPanelHeight))
transition.updateFrame(node: self.textBackgroundNode, frame: CGRect(x: leftInset, y: (topPanelHeight - fieldHeight) / 2.0, width: size.width - leftInset - rightInset, height: fieldHeight))
transition.updateFrame(node: self.textFieldNode, frame: CGRect(x: leftInset + 24.0, y: (topPanelHeight - fieldHeight) / 2.0 + 1.0, width: size.width - leftInset - rightInset - 36.0, height: fieldHeight - 2.0))
let prefixSize = self.prefixNode.measure(CGSize(width: size.width, height: fieldHeight))
transition.updateFrame(node: self.prefixNode, frame: CGRect(origin: CGPoint(x: leftInset + 13.0, y: 12.0 + UIScreenPixel), size: prefixSize))
transition.updateFrame(node: self.doneButton, frame: CGRect(x: 0.0, y: size.width - rightInset + buttonSpacing, width: topPanelHeight, height: topPanelHeight))
let colorPickerSize = CGSize(width: size.width, height: size.height - topPanelHeight - separatorHeight)
transition.updateFrame(node: self.colorPickerNode, frame: CGRect(origin: CGPoint(x: 0.0, y: topPanelHeight + separatorHeight), size: colorPickerSize))
self.colorPickerNode.updateLayout(size: colorPickerSize, transition: transition)
}
@objc internal func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if string.count > 1 {
if string.count <= 6 {
var updated = textField.text ?? ""
updated.replaceSubrange(updated.index(updated.startIndex, offsetBy: range.lowerBound) ..< updated.index(updated.startIndex, offsetBy: range.upperBound), with: string)
if updated.count <= 6 && updated.rangeOfCharacter(from: CharacterSet(charactersIn: "0123456789abcdefABCDEF").inverted) == nil {
textField.text = updated.uppercased()
}
}
return false
} else if string.count == 1 {
return (textField.text ?? "").count < 6 && string.rangeOfCharacter(from: CharacterSet(charactersIn: "0123456789abcdefABCDEF").inverted) == nil
}
return true
}
@objc func textFieldTextChanged(_ sender: UITextField) {
if let text = sender.text, text.count == 6, let color = UIColor(hexString: text) {
self.setColor(color)
}
}
@objc func textFieldShouldReturn(_ textField: UITextField) -> Bool {
self.textFieldNode.resignFirstResponder()
return false
}
@objc func textFieldDidEndEditing(_ textField: UITextField) {
if let text = self.textFieldNode.textField.text, text.count == 6, let color = UIColor(hexString: text) {
self.setColor(color)
} else {
self.setColor(.black)
}
}
}