Switch to new check node implementation

This commit is contained in:
Ilya Laktyushin 2021-02-08 21:55:41 +04:00
parent 838f16781e
commit 249b684e64
21 changed files with 407 additions and 359 deletions

View File

@ -250,7 +250,7 @@ public class ChatListAdditionalCategoryItemNode: ItemListRevealOptionsItemNode {
selectionNode = current selectionNode = current
updatedSelectionNode = selectionNode updatedSelectionNode = selectionNode
} else { } else {
selectionNode = CheckNode(strokeColor: item.presentationData.theme.list.itemCheckColors.strokeColor, fillColor: item.presentationData.theme.list.itemCheckColors.fillColor, foregroundColor: item.presentationData.theme.list.itemCheckColors.foregroundColor, style: .plain) selectionNode = CheckNode(theme: CheckNodeTheme(theme: item.presentationData.theme, style: .plain))
selectionNode.isUserInteractionEnabled = false selectionNode.isUserInteractionEnabled = false
updatedSelectionNode = selectionNode updatedSelectionNode = selectionNode
} }
@ -322,9 +322,9 @@ public class ChatListAdditionalCategoryItemNode: ItemListRevealOptionsItemNode {
strongSelf.selectionNode = updatedSelectionNode strongSelf.selectionNode = updatedSelectionNode
strongSelf.addSubnode(updatedSelectionNode) strongSelf.addSubnode(updatedSelectionNode)
} }
updatedSelectionNode.setIsChecked(isSelected, animated: animated) updatedSelectionNode.setSelected(isSelected, animated: animated)
updatedSelectionNode.frame = CGRect(origin: CGPoint(x: params.width - params.rightInset - 32.0 - 12.0, y: floor((nodeLayout.contentSize.height - 32.0) / 2.0)), size: CGSize(width: 32.0, height: 32.0)) updatedSelectionNode.frame = CGRect(origin: CGPoint(x: params.width - params.rightInset - 22.0 - 17.0, y: floor((nodeLayout.contentSize.height - 22.0) / 2.0)), size: CGSize(width: 22.0, height: 22.0))
} else if let selectionNode = strongSelf.selectionNode { } else if let selectionNode = strongSelf.selectionNode {
selectionNode.removeFromSupernode() selectionNode.removeFromSupernode()
strongSelf.selectionNode = nil strongSelf.selectionNode = nil

View File

@ -10,6 +10,7 @@ swift_library(
"//submodules/AsyncDisplayKit:AsyncDisplayKit", "//submodules/AsyncDisplayKit:AsyncDisplayKit",
"//submodules/Display:Display", "//submodules/Display:Display",
"//submodules/LegacyComponents:LegacyComponents", "//submodules/LegacyComponents:LegacyComponents",
"//submodules/TelegramPresentationData:TelegramPresentationData",
], ],
visibility = [ visibility = [
"//visibility:public", "//visibility:public",

View File

@ -1,82 +1,292 @@
import Foundation import Foundation
import UIKit import UIKit
import AsyncDisplayKit import AsyncDisplayKit
import Display
import LegacyComponents import LegacyComponents
import TelegramPresentationData
public enum CheckNodeStyle { public struct CheckNodeTheme {
case plain public let backgroundColor: UIColor
case overlay public let strokeColor: UIColor
case navigation public let borderColor: UIColor
case compact public let overlayBorder: Bool
} public let hasInset: Bool
public let hasShadow: Bool
public final class CheckNode: ASDisplayNode { public let filledBorder: Bool
private var strokeColor: UIColor public let borderWidth: CGFloat?
private var fillColor: UIColor
private var foregroundColor: UIColor
private let checkStyle: CheckNodeStyle
private var checkView: TGCheckButtonView? public init(backgroundColor: UIColor, strokeColor: UIColor, borderColor: UIColor, overlayBorder: Bool, hasInset: Bool, hasShadow: Bool, filledBorder: Bool = false, borderWidth: CGFloat? = nil) {
self.backgroundColor = backgroundColor
public private(set) var isChecked: Bool = false
private weak var target: AnyObject?
private var action: Selector?
public init(strokeColor: UIColor, fillColor: UIColor, foregroundColor: UIColor, style: CheckNodeStyle) {
self.strokeColor = strokeColor self.strokeColor = strokeColor
self.fillColor = fillColor self.borderColor = borderColor
self.foregroundColor = foregroundColor self.overlayBorder = overlayBorder
self.checkStyle = style self.hasInset = hasInset
self.hasShadow = hasShadow
super.init() self.filledBorder = filledBorder
} self.borderWidth = borderWidth
}
override public func didLoad() { }
super.didLoad()
public extension CheckNodeTheme {
let style: TGCheckButtonStyle enum Style {
let checkSize: CGSize case plain
switch self.checkStyle { case overlay
case .plain: }
style = TGCheckButtonStyleDefault
checkSize = CGSize(width: 32.0, height: 32.0) init(theme: PresentationTheme, style: Style, hasInset: Bool = false) {
case .overlay: let borderColor: UIColor
style = TGCheckButtonStyleMedia var hasInset = hasInset
checkSize = CGSize(width: 32.0, height: 32.0) let overlayBorder: Bool
case .navigation: let hasShadow: Bool
style = TGCheckButtonStyleGallery switch style {
checkSize = CGSize(width: 39.0, height: 39.0) case .plain:
case .compact: borderColor = theme.list.itemCheckColors.strokeColor
style = TGCheckButtonStyleCompact overlayBorder = false
checkSize = CGSize(width: 30.0, height: 30.0) hasShadow = false
} case .overlay:
let checkView = TGCheckButtonView(style: style, pallete: TGCheckButtonPallete(defaultBackgroundColor: self.fillColor, accentBackgroundColor: self.fillColor, defaultBorderColor: self.strokeColor, mediaBorderColor: self.strokeColor, chatBorderColor: self.strokeColor, check: self.foregroundColor, blueColor: self.fillColor, barBackgroundColor: self.fillColor))! borderColor = UIColor(rgb: 0xffffff)
checkView.setSelected(true, animated: false) hasInset = true
checkView.layoutSubviews() overlayBorder = true
checkView.setSelected(self.isChecked, animated: false) hasShadow = true
if let target = self.target, let action = self.action { }
checkView.addTarget(target, action: action, for: .touchUpInside)
} self.init(backgroundColor: theme.list.itemCheckColors.fillColor, strokeColor: theme.list.itemCheckColors.foregroundColor, borderColor: borderColor, overlayBorder: overlayBorder, hasInset: hasInset, hasShadow: hasShadow)
self.checkView = checkView }
self.view.addSubview(checkView) }
checkView.frame = CGRect(origin: CGPoint(), size: checkSize) public enum CheckNodeContent {
} case check
case counter(Int)
public func setIsChecked(_ isChecked: Bool, animated: Bool) { }
if isChecked != self.isChecked {
self.isChecked = isChecked private final class CheckNodeParameters: NSObject {
self.checkView?.setSelected(isChecked, animated: animated) let theme: CheckNodeTheme
} let content: CheckNodeContent
} let animationProgress: CGFloat
let selected: Bool
public func addTarget(target: AnyObject?, action: Selector) { let animatingOut: Bool
self.target = target
self.action = action init(theme: CheckNodeTheme, content: CheckNodeContent, animationProgress: CGFloat, selected: Bool, animatingOut: Bool) {
if self.isNodeLoaded { self.theme = theme
self.checkView?.addTarget(target, action: action, for: .touchUpInside) self.content = content
} self.animationProgress = animationProgress
self.selected = selected
self.animatingOut = animatingOut
}
}
public class CheckNode: ASDisplayNode {
private var animatingOut = false
private var animationProgress: CGFloat = 0.0
public var theme: CheckNodeTheme {
didSet {
self.setNeedsDisplay()
}
}
public init(theme: CheckNodeTheme, content: CheckNodeContent = .check) {
self.theme = theme
self.content = content
super.init()
self.isOpaque = false
}
public var content: CheckNodeContent {
didSet {
self.setNeedsDisplay()
}
}
public var selected = false
public func setSelected(_ selected: Bool, animated: Bool = false) {
guard self.selected != selected else {
return
}
self.selected = selected
if animated {
self.animatingOut = !selected
let animation = POPBasicAnimation()
animation.property = (POPAnimatableProperty.property(withName: "progress", initializer: { property in
property?.readBlock = { node, values in
values?.pointee = (node as! CheckNode).animationProgress
}
property?.writeBlock = { node, values in
(node as! CheckNode).animationProgress = values!.pointee
(node as! CheckNode).setNeedsDisplay()
}
property?.threshold = 0.01
}) as! POPAnimatableProperty)
animation.fromValue = (selected ? 0.0 : 1.0) as NSNumber
animation.toValue = (selected ? 1.0 : 0.0) as NSNumber
animation.timingFunction = CAMediaTimingFunction(name: selected ? CAMediaTimingFunctionName.easeOut : CAMediaTimingFunctionName.easeIn)
animation.duration = selected ? 0.21 : 0.15
self.pop_add(animation, forKey: "progress")
} else {
self.pop_removeAllAnimations()
self.animatingOut = false
self.animationProgress = selected ? 1.0 : 0.0
self.setNeedsDisplay()
}
}
public func setHighlighted(_ highlighted: Bool, animated: Bool = false) {
}
override public func drawParameters(forAsyncLayer layer: _ASDisplayLayer) -> NSObjectProtocol? {
return CheckNodeParameters(theme: self.theme, content: self.content, animationProgress: self.animationProgress, selected: self.selected, animatingOut: self.animatingOut)
}
@objc override public class func draw(_ bounds: CGRect, withParameters parameters: Any?, isCancelled: () -> Bool, isRasterizing: Bool) {
let context = UIGraphicsGetCurrentContext()!
if !isRasterizing {
context.setBlendMode(.copy)
context.setFillColor(UIColor.clear.cgColor)
context.fill(bounds)
}
if let parameters = parameters as? CheckNodeParameters {
let center = CGPoint(x: bounds.width / 2.0, y: bounds.width / 2.0)
var borderWidth: CGFloat = 1.0 + UIScreenPixel
if parameters.theme.hasInset {
borderWidth = 1.5
}
if let customBorderWidth = parameters.theme.borderWidth {
borderWidth = customBorderWidth
}
let checkWidth: CGFloat = 1.5
let inset: CGFloat = parameters.theme.hasInset ? 2.0 - UIScreenPixel : 0.0
let checkProgress = parameters.animatingOut ? 1.0 : parameters.animationProgress
let fillProgress = parameters.animatingOut ? 1.0 : min(1.0, parameters.animationProgress * 1.35)
context.setStrokeColor(parameters.theme.borderColor.cgColor)
context.setLineWidth(borderWidth)
let maybeScaleOut = {
if parameters.animatingOut {
context.translateBy(x: bounds.width / 2.0, y: bounds.height / 2.0)
context.scaleBy(x: parameters.animationProgress, y: parameters.animationProgress)
context.translateBy(x: -bounds.width / 2.0, y: -bounds.height / 2.0)
context.setAlpha(parameters.animationProgress)
}
}
let borderInset = borderWidth / 2.0 + inset
let borderProgress: CGFloat = parameters.theme.filledBorder ? fillProgress : 1.0
let borderFrame = bounds.insetBy(dx: borderInset, dy: borderInset)
if parameters.theme.filledBorder {
maybeScaleOut()
}
context.saveGState()
if parameters.theme.hasShadow {
context.setShadow(offset: CGSize(), blur: 2.5, color: UIColor(rgb: 0x000000, alpha: 0.22).cgColor)
}
context.strokeEllipse(in: borderFrame.insetBy(dx: borderFrame.width * (1.0 - borderProgress), dy: borderFrame.height * (1.0 - borderProgress)))
context.restoreGState()
if !parameters.theme.filledBorder {
maybeScaleOut()
}
context.setFillColor(parameters.theme.backgroundColor.cgColor)
let fillInset = parameters.theme.overlayBorder ? borderWidth + inset : inset
let fillFrame = bounds.insetBy(dx: fillInset, dy: fillInset)
context.fillEllipse(in: fillFrame.insetBy(dx: fillFrame.width * (1.0 - fillProgress), dy: fillFrame.height * (1.0 - fillProgress)))
let scale = (bounds.width - inset) / 18.0
let firstSegment: CGFloat = max(0.0, min(1.0, checkProgress * 3.0))
let s = CGPoint(x: center.x - (4.0 - 0.3333) * scale, y: center.y + 0.5 * scale)
let p1 = CGPoint(x: 2.5 * scale, y: 3.0 * scale)
let p2 = CGPoint(x: 4.6667 * scale, y: -6.0 * scale)
if !firstSegment.isZero {
if firstSegment < 1.0 {
context.move(to: CGPoint(x: s.x + p1.x * firstSegment, y: s.y + p1.y * firstSegment))
context.addLine(to: s)
} else {
let secondSegment = (checkProgress - 0.33) * 1.5
context.move(to: CGPoint(x: s.x + p1.x + p2.x * secondSegment, y: s.y + p1.y + p2.y * secondSegment))
context.addLine(to: CGPoint(x: s.x + p1.x, y: s.y + p1.y))
context.addLine(to: s)
}
}
context.setStrokeColor(parameters.theme.strokeColor.cgColor)
if parameters.theme.strokeColor == .clear {
context.setBlendMode(.clear)
}
context.setLineWidth(checkWidth)
context.setLineCap(.round)
context.setLineJoin(.round)
context.setMiterLimit(10.0)
context.strokePath()
}
}
override public func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesBegan(touches, with: event)
}
override public func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesEnded(touches, with: event)
}
override public func touchesCancelled(_ touches: Set<UITouch>?, with event: UIEvent?) {
super.touchesCancelled(touches, with: event)
}
}
public class InteractiveCheckNode: CheckNode {
private let buttonNode: HighlightTrackingButtonNode
public var valueChanged: ((Bool) -> Void)?
override public init(theme: CheckNodeTheme, content: CheckNodeContent = .check) {
self.buttonNode = HighlightTrackingButtonNode()
super.init(theme: theme, content: content)
self.addSubnode(self.buttonNode)
self.buttonNode.addTarget(self, action: #selector(buttonPressed), forControlEvents: .touchUpInside)
self.buttonNode.highligthedChanged = { [weak self] highlighted in
guard let strongSelf = self else {
return
}
if highlighted {
let transition: ContainedViewLayoutTransition = .animated(duration: 0.3, curve: .spring)
transition.updateTransformScale(node: strongSelf, scale: 0.85)
} else {
let transition: ContainedViewLayoutTransition = .animated(duration: 0.5, curve: .spring)
transition.updateTransformScale(node: strongSelf, scale: 1.0)
}
}
}
@objc private func buttonPressed() {
self.setSelected(!self.selected, animated: true)
self.valueChanged?(self.selected)
}
public override func layout() {
super.layout()
self.buttonNode.frame = self.bounds
} }
} }

View File

@ -1,168 +0,0 @@
import Foundation
import UIKit
import AsyncDisplayKit
import Display
import LegacyComponents
public struct CheckNodeTheme {
public let backgroundColor: UIColor
public let strokeColor: UIColor
public let borderColor: UIColor
public let hasShadow: Bool
public init(backgroundColor: UIColor, strokeColor: UIColor, borderColor: UIColor, hasShadow: Bool) {
self.backgroundColor = backgroundColor
self.strokeColor = strokeColor
self.borderColor = borderColor
self.hasShadow = hasShadow
}
}
public enum CheckNodeContent {
case check
case counter(Int)
}
private final class CheckNodeParameters: NSObject {
let theme: CheckNodeTheme
let content: CheckNodeContent
let animationProgress: CGFloat
let selected: Bool
init(theme: CheckNodeTheme, content: CheckNodeContent, animationProgress: CGFloat, selected: Bool) {
self.theme = theme
self.content = content
self.animationProgress = animationProgress
self.selected = selected
}
}
public class ModernCheckNode: ASDisplayNode {
private var animationProgress: CGFloat = 0.0
public var theme: CheckNodeTheme {
didSet {
self.setNeedsDisplay()
}
}
public init(theme: CheckNodeTheme, content: CheckNodeContent = .check) {
self.theme = theme
self.content = content
super.init()
self.isOpaque = false
}
public var content: CheckNodeContent {
didSet {
self.setNeedsDisplay()
}
}
public var selected = false
public func setSelected(_ selected: Bool, animated: Bool = false) {
guard self.selected != selected else {
return
}
self.selected = selected
if selected && animated {
let animation = POPBasicAnimation()
animation.property = (POPAnimatableProperty.property(withName: "progress", initializer: { property in
property?.readBlock = { node, values in
values?.pointee = (node as! ModernCheckNode).animationProgress
}
property?.writeBlock = { node, values in
(node as! ModernCheckNode).animationProgress = values!.pointee
(node as! ModernCheckNode).setNeedsDisplay()
}
property?.threshold = 0.01
}) as! POPAnimatableProperty)
animation.fromValue = 0.0 as NSNumber
animation.toValue = 1.0 as NSNumber
animation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.linear)
animation.duration = 0.21
self.pop_add(animation, forKey: "progress")
} else {
self.pop_removeAllAnimations()
self.animationProgress = selected ? 1.0 : 0.0
self.setNeedsDisplay()
}
}
public func setHighlighted(_ highlighted: Bool, animated: Bool = false) {
}
override public func drawParameters(forAsyncLayer layer: _ASDisplayLayer) -> NSObjectProtocol? {
return CheckNodeParameters(theme: self.theme, content: self.content, animationProgress: self.animationProgress, selected: self.selected)
}
@objc override public class func draw(_ bounds: CGRect, withParameters parameters: Any?, isCancelled: () -> Bool, isRasterizing: Bool) {
let context = UIGraphicsGetCurrentContext()!
if !isRasterizing {
context.setBlendMode(.copy)
context.setFillColor(UIColor.clear.cgColor)
context.fill(bounds)
}
if let parameters = parameters as? CheckNodeParameters {
let progress = parameters.animationProgress
let diameter = bounds.width
let center = CGPoint(x: diameter / 2.0, y: diameter / 2.0)
var borderWidth: CGFloat = 1.5
if UIScreenScale == 3.0 {
borderWidth = 5.0 / 3.0
}
context.setStrokeColor(parameters.theme.borderColor.cgColor)
context.setLineWidth(borderWidth)
context.strokeEllipse(in: bounds.insetBy(dx: borderWidth / 2.0, dy: borderWidth / 2.0))
context.setFillColor(parameters.theme.backgroundColor.cgColor)
context.fillEllipse(in: bounds.insetBy(dx: (diameter - borderWidth) * (1.0 - parameters.animationProgress), dy: (diameter - borderWidth) * (1.0 - parameters.animationProgress)))
let firstSegment: CGFloat = max(0.0, min(1.0, progress * 3.0))
let s = CGPoint(x: center.x - 4.0, y: center.y + UIScreenPixel)
let p1 = CGPoint(x: 3.0, y: 3.0)
let p2 = CGPoint(x: 5.0, y: -6.0)
if !firstSegment.isZero {
if firstSegment < 1.0 {
context.move(to: CGPoint(x: s.x + p1.x * firstSegment, y: s.y + p1.y * firstSegment))
context.addLine(to: s)
} else {
let secondSegment = (progress - 0.33) * 1.5
context.move(to: CGPoint(x: s.x + p1.x + p2.x * secondSegment, y: s.y + p1.y + p2.y * secondSegment))
context.addLine(to: CGPoint(x: s.x + p1.x, y: s.y + p1.y))
context.addLine(to: s)
}
}
context.setStrokeColor(parameters.theme.strokeColor.cgColor)
if parameters.theme.strokeColor == .clear {
context.setBlendMode(.clear)
}
context.setLineWidth(borderWidth)
context.setLineCap(.round)
context.setLineJoin(.round)
context.setMiterLimit(10.0)
context.strokePath()
}
}
override public func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesBegan(touches, with: event)
}
override public func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesEnded(touches, with: event)
}
override public func touchesCancelled(_ touches: Set<UITouch>?, with event: UIEvent?) {
super.touchesCancelled(touches, with: event)
}
}

View File

@ -97,7 +97,7 @@ class CreatePollOptionItemNode: ItemListRevealOptionsItemNode, ItemListItemNode,
private let bottomStripeNode: ASDisplayNode private let bottomStripeNode: ASDisplayNode
private let maskNode: ASImageNode private let maskNode: ASImageNode
private var checkNode: CheckNode? private var checkNode: InteractiveCheckNode?
private let textClippingNode: ASDisplayNode private let textClippingNode: ASDisplayNode
private let textNode: EditableTextNode private let textNode: EditableTextNode
@ -162,10 +162,6 @@ class CreatePollOptionItemNode: ItemListRevealOptionsItemNode, ItemListItemNode,
self.containerNode.addSubnode(self.textLimitNode) self.containerNode.addSubnode(self.textLimitNode)
} }
@objc private func checkNodePressed() {
self.item?.toggleSelected()
}
override func didLoad() { override func didLoad() {
super.didLoad() super.didLoad()
@ -360,16 +356,18 @@ class CreatePollOptionItemNode: ItemListRevealOptionsItemNode, ItemListItemNode,
strongSelf.textNode.keyboardAppearance = item.presentationData.theme.rootController.keyboardColor.keyboardAppearance strongSelf.textNode.keyboardAppearance = item.presentationData.theme.rootController.keyboardColor.keyboardAppearance
let checkSize = CGSize(width: 32.0, height: 32.0) let checkSize = CGSize(width: 22.0, height: 22.0)
let checkFrame = CGRect(origin: CGPoint(x: params.leftInset + revealOffset + 11.0, y: floor((layout.contentSize.height - checkSize.height) / 2.0)), size: checkSize) let checkFrame = CGRect(origin: CGPoint(x: params.leftInset + revealOffset + 16.0, y: floor((layout.contentSize.height - checkSize.height) / 2.0)), size: checkSize)
if let isSelected = item.isSelected { if let isSelected = item.isSelected {
if let checkNode = strongSelf.checkNode { if let checkNode = strongSelf.checkNode {
transition.updateFrame(node: checkNode, frame: checkFrame) transition.updateFrame(node: checkNode, frame: checkFrame)
checkNode.setIsChecked(isSelected, animated: true) checkNode.setSelected(isSelected, animated: true)
} else { } else {
let checkNode = CheckNode(strokeColor: item.presentationData.theme.list.itemCheckColors.strokeColor, fillColor: item.presentationData.theme.list.itemSwitchColors.positiveColor, foregroundColor: item.presentationData.theme.list.itemCheckColors.foregroundColor, style: .plain) let checkNode = InteractiveCheckNode(theme: CheckNodeTheme(backgroundColor: item.presentationData.theme.list.itemSwitchColors.positiveColor, strokeColor: item.presentationData.theme.list.itemCheckColors.foregroundColor, borderColor: item.presentationData.theme.list.itemCheckColors.strokeColor, overlayBorder: false, hasInset: false, hasShadow: false))
checkNode.addTarget(target: strongSelf, action: #selector(strongSelf.checkNodePressed)) checkNode.setSelected(isSelected, animated: false)
checkNode.setIsChecked(isSelected, animated: false) checkNode.valueChanged = { [weak self] value in
self?.item?.toggleSelected()
}
strongSelf.checkNode = checkNode strongSelf.checkNode = checkNode
strongSelf.containerNode.addSubnode(checkNode) strongSelf.containerNode.addSubnode(checkNode)
checkNode.frame = checkFrame checkNode.frame = checkFrame

View File

@ -535,7 +535,7 @@ public class ContactsPeerItemNode: ItemListRevealOptionsItemNode {
selectionNode = current selectionNode = current
updatedSelectionNode = selectionNode updatedSelectionNode = selectionNode
} else { } else {
selectionNode = CheckNode(strokeColor: item.presentationData.theme.list.itemCheckColors.strokeColor, fillColor: item.presentationData.theme.list.itemCheckColors.fillColor, foregroundColor: item.presentationData.theme.list.itemCheckColors.foregroundColor, style: .plain) selectionNode = CheckNode(theme: CheckNodeTheme(theme: item.presentationData.theme, style: .plain))
selectionNode.isUserInteractionEnabled = false selectionNode.isUserInteractionEnabled = false
updatedSelectionNode = selectionNode updatedSelectionNode = selectionNode
} }
@ -1004,9 +1004,9 @@ public class ContactsPeerItemNode: ItemListRevealOptionsItemNode {
strongSelf.selectionNode = updatedSelectionNode strongSelf.selectionNode = updatedSelectionNode
strongSelf.addSubnode(updatedSelectionNode) strongSelf.addSubnode(updatedSelectionNode)
} }
updatedSelectionNode.setIsChecked(isSelected, animated: animated) updatedSelectionNode.setSelected(isSelected, animated: animated)
updatedSelectionNode.frame = CGRect(origin: CGPoint(x: params.width - params.rightInset - 32.0 - 12.0, y: floor((nodeLayout.contentSize.height - 32.0) / 2.0)), size: CGSize(width: 32.0, height: 32.0)) updatedSelectionNode.frame = CGRect(origin: CGPoint(x: params.width - params.rightInset - 22.0 - 17.0, y: floor((nodeLayout.contentSize.height - 22.0) / 2.0)), size: CGSize(width: 22.0, height: 22.0))
} else if let selectionNode = strongSelf.selectionNode { } else if let selectionNode = strongSelf.selectionNode {
selectionNode.removeFromSupernode() selectionNode.removeFromSupernode()
strongSelf.selectionNode = nil strongSelf.selectionNode = nil

View File

@ -74,13 +74,14 @@ public class ActionSheetCheckboxItemNode: ActionSheetItemNode {
self.checkNode = ASImageNode() self.checkNode = ASImageNode()
self.checkNode.isUserInteractionEnabled = false self.checkNode.isUserInteractionEnabled = false
self.checkNode.displaysAsynchronously = false self.checkNode.displaysAsynchronously = false
self.checkNode.image = generateImage(CGSize(width: 14.0, height: 11.0), rotatedContext: { size, context in self.checkNode.image = generateImage(CGSize(width: 14.0, height: 12.0), rotatedContext: { size, context in
context.clear(CGRect(origin: CGPoint(), size: size)) context.clear(CGRect(origin: CGPoint(), size: size))
context.setStrokeColor(theme.controlAccentColor.cgColor) context.setStrokeColor(theme.controlAccentColor.cgColor)
context.setLineWidth(2.0) context.setLineWidth(2.0 - UIScreenPixel)
context.move(to: CGPoint(x: 12.0, y: 1.0)) context.setLineCap(.round)
context.addLine(to: CGPoint(x: 4.16482734, y: 9.0)) context.move(to: CGPoint(x: 13.0, y: 1.0))
context.addLine(to: CGPoint(x: 1.0, y: 5.81145833)) context.addLine(to: CGPoint(x: 5.0, y: 11.0))
context.addLine(to: CGPoint(x: 1.0, y: 7.0))
context.strokePath() context.strokePath()
}) })
self.checkNode.isAccessibilityElement = false self.checkNode.isAccessibilityElement = false
@ -146,8 +147,8 @@ public class ActionSheetCheckboxItemNode: ActionSheetItemNode {
self.button.frame = CGRect(origin: CGPoint(), size: size) self.button.frame = CGRect(origin: CGPoint(), size: size)
var titleOrigin: CGFloat = 44.0 var titleOrigin: CGFloat = 50.0
var checkOrigin: CGFloat = 22.0 var checkOrigin: CGFloat = 27.0
if let item = self.item, item.style == .alignRight { if let item = self.item, item.style == .alignRight {
titleOrigin = 24.0 titleOrigin = 24.0
checkOrigin = size.width - 22.0 checkOrigin = size.width - 22.0

View File

@ -15,11 +15,13 @@ public final class AlertControllerTheme: Equatable {
public let primaryColor: UIColor public let primaryColor: UIColor
public let secondaryColor: UIColor public let secondaryColor: UIColor
public let accentColor: UIColor public let accentColor: UIColor
public let contrastColor: UIColor
public let destructiveColor: UIColor public let destructiveColor: UIColor
public let disabledColor: UIColor public let disabledColor: UIColor
public let controlBorderColor: UIColor
public let baseFontSize: CGFloat public let baseFontSize: CGFloat
public init(backgroundType: ActionSheetControllerThemeBackgroundType, backgroundColor: UIColor, separatorColor: UIColor, highlightedItemColor: UIColor, primaryColor: UIColor, secondaryColor: UIColor, accentColor: UIColor, destructiveColor: UIColor, disabledColor: UIColor, baseFontSize: CGFloat) { public init(backgroundType: ActionSheetControllerThemeBackgroundType, backgroundColor: UIColor, separatorColor: UIColor, highlightedItemColor: UIColor, primaryColor: UIColor, secondaryColor: UIColor, accentColor: UIColor, contrastColor: UIColor, destructiveColor: UIColor, disabledColor: UIColor, controlBorderColor: UIColor, baseFontSize: CGFloat) {
self.backgroundType = backgroundType self.backgroundType = backgroundType
self.backgroundColor = backgroundColor self.backgroundColor = backgroundColor
self.separatorColor = separatorColor self.separatorColor = separatorColor
@ -27,8 +29,10 @@ public final class AlertControllerTheme: Equatable {
self.primaryColor = primaryColor self.primaryColor = primaryColor
self.secondaryColor = secondaryColor self.secondaryColor = secondaryColor
self.accentColor = accentColor self.accentColor = accentColor
self.contrastColor = contrastColor
self.destructiveColor = destructiveColor self.destructiveColor = destructiveColor
self.disabledColor = disabledColor self.disabledColor = disabledColor
self.controlBorderColor = controlBorderColor
self.baseFontSize = baseFontSize self.baseFontSize = baseFontSize
} }

View File

@ -6,14 +6,22 @@ import TelegramPresentationData
import CheckNode import CheckNode
public final class GalleryNavigationCheckNode: ASDisplayNode, NavigationButtonCustomDisplayNode { public final class GalleryNavigationCheckNode: ASDisplayNode, NavigationButtonCustomDisplayNode {
private var checkNode: CheckNode private var checkNode: InteractiveCheckNode
private weak var target: AnyObject?
private var action: Selector?
public init(theme: PresentationTheme) { public init(theme: PresentationTheme) {
self.checkNode = CheckNode(strokeColor: theme.list.itemCheckColors.strokeColor, fillColor: theme.list.itemCheckColors.fillColor, foregroundColor: theme.list.itemCheckColors.foregroundColor, style: .navigation) self.checkNode = InteractiveCheckNode(theme: CheckNodeTheme(theme: theme, style: .overlay))
super.init() super.init()
self.addSubnode(self.checkNode) self.addSubnode(self.checkNode)
self.checkNode.valueChanged = { [weak self] value in
if let strongSelf = self, let target = strongSelf.target, let action = strongSelf.action {
let _ = target.perform(action)
}
}
} }
public var isHighlightable: Bool { public var isHighlightable: Bool {
@ -21,15 +29,16 @@ public final class GalleryNavigationCheckNode: ASDisplayNode, NavigationButtonCu
} }
public var isChecked: Bool { public var isChecked: Bool {
return self.checkNode.isChecked return self.checkNode.selected
} }
public func setIsChecked(_ isChecked: Bool, animated: Bool) { public func setIsChecked(_ isChecked: Bool, animated: Bool) {
self.checkNode.setIsChecked(isChecked, animated: animated) self.checkNode.setSelected(isChecked, animated: animated)
} }
public func addTarget(target: AnyObject?, action: Selector) { public func addTarget(target: AnyObject?, action: Selector) {
self.checkNode.addTarget(target: target, action: action) self.target = target
self.action = action
} }
override public func calculateSizeThatFits(_ constrainedSize: CGSize) -> CGSize { override public func calculateSizeThatFits(_ constrainedSize: CGSize) -> CGSize {
@ -40,7 +49,7 @@ public final class GalleryNavigationCheckNode: ASDisplayNode, NavigationButtonCu
super.layout() super.layout()
let size = self.bounds.size let size = self.bounds.size
let checkSize = CGSize(width: 39.0, height: 39.0) let checkSize = CGSize(width: 36.0, height: 36.0)
self.checkNode.frame = CGRect(origin: CGPoint(x: floor((size.width - checkSize.width) / 2.0) + 11.0, y: floor((size.height - checkSize.height) / 2.0) + 3.0), size: checkSize) self.checkNode.frame = CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - checkSize.width) / 2.0) + 11.0, y: floorToScreenPixels((size.height - checkSize.height) / 2.0) + 3.0), size: checkSize)
} }
} }

View File

@ -13,7 +13,7 @@ public final class GridMessageSelectionNode: ASDisplayNode {
public init(theme: PresentationTheme, toggle: @escaping (Bool) -> Void) { public init(theme: PresentationTheme, toggle: @escaping (Bool) -> Void) {
self.toggle = toggle self.toggle = toggle
self.checkNode = CheckNode(strokeColor: theme.list.itemCheckColors.strokeColor, fillColor: theme.list.itemCheckColors.fillColor, foregroundColor: theme.list.itemCheckColors.foregroundColor, style: .overlay) self.checkNode = CheckNode(theme: CheckNodeTheme(theme: theme, style: .overlay, hasInset: true))
self.checkNode.isUserInteractionEnabled = false self.checkNode.isUserInteractionEnabled = false
super.init() super.init()
@ -42,7 +42,7 @@ public final class GridMessageSelectionNode: ASDisplayNode {
public func updateSelected(_ selected: Bool, animated: Bool) { public func updateSelected(_ selected: Bool, animated: Bool) {
if self.selected != selected { if self.selected != selected {
self.selected = selected self.selected = selected
self.checkNode.setIsChecked(selected, animated: animated) self.checkNode.setSelected(selected, animated: animated)
} }
} }
@ -55,7 +55,7 @@ public final class GridMessageSelectionNode: ASDisplayNode {
override public func layout() { override public func layout() {
super.layout() super.layout()
let checkSize = CGSize(width: 32.0, height: 32.0) let checkSize = CGSize(width: 28.0, height: 28.0)
self.checkNode.frame = CGRect(origin: CGPoint(x: self.bounds.size.width - checkSize.width, y: 0.0), size: checkSize) self.checkNode.frame = CGRect(origin: CGPoint(x: self.bounds.size.width - checkSize.width - 2.0, y: 2.0), size: checkSize)
} }
} }

View File

@ -8,7 +8,7 @@ public final class ItemListSelectableControlNode: ASDisplayNode {
private let checkNode: CheckNode private let checkNode: CheckNode
public init(strokeColor: UIColor, fillColor: UIColor, foregroundColor: UIColor) { public init(strokeColor: UIColor, fillColor: UIColor, foregroundColor: UIColor) {
self.checkNode = CheckNode(strokeColor: strokeColor, fillColor: fillColor, foregroundColor: foregroundColor, style: .plain) self.checkNode = CheckNode(theme: CheckNodeTheme(backgroundColor: fillColor, strokeColor: foregroundColor, borderColor: strokeColor, overlayBorder: false, hasInset: true, hasShadow: false))
self.checkNode.isUserInteractionEnabled = false self.checkNode.isUserInteractionEnabled = false
super.init() super.init()
@ -26,9 +26,9 @@ public final class ItemListSelectableControlNode: ASDisplayNode {
} }
return (compact ? 38.0 : 45.0, { size, animated in return (compact ? 38.0 : 45.0, { size, animated in
let checkSize = CGSize(width: 32.0, height: 32.0) let checkSize = CGSize(width: 26.0, height: 26.0)
resultNode.checkNode.frame = CGRect(origin: CGPoint(x: compact ? 9 : 12.0, y: floor((size.height - checkSize.height) / 2.0)), size: checkSize) resultNode.checkNode.frame = CGRect(origin: CGPoint(x: compact ? 11.0 : 13.0, y: floorToScreenPixels((size.height - checkSize.height) / 2.0)), size: checkSize)
resultNode.checkNode.setIsChecked(selected, animated: animated) resultNode.checkNode.setSelected(selected, animated: animated)
return resultNode return resultNode
}) })
} }

View File

@ -20,6 +20,7 @@ swift_library(
"//submodules/ContextUI:ContextUI", "//submodules/ContextUI:ContextUI",
"//submodules/LocalizedPeerData:LocalizedPeerData", "//submodules/LocalizedPeerData:LocalizedPeerData",
"//submodules/AccountContext:AccountContext", "//submodules/AccountContext:AccountContext",
"//submodules/CheckNode:CheckNode",
], ],
visibility = [ visibility = [
"//visibility:public", "//visibility:public",

View File

@ -13,6 +13,7 @@ import LegacyComponents
import ContextUI import ContextUI
import LocalizedPeerData import LocalizedPeerData
import AccountContext import AccountContext
import CheckNode
private let avatarFont = avatarPlaceholderFont(size: 24.0) private let avatarFont = avatarPlaceholderFont(size: 24.0)
private let textFont = Font.regular(11.0) private let textFont = Font.regular(11.0)
@ -71,7 +72,7 @@ public final class SelectablePeerNode: ASDisplayNode {
private let avatarNodeContainer: ASDisplayNode private let avatarNodeContainer: ASDisplayNode
private let avatarNode: AvatarNode private let avatarNode: AvatarNode
private let onlineNode: PeerOnlineMarkerNode private let onlineNode: PeerOnlineMarkerNode
private var checkView: TGCheckButtonView? private var checkNode: CheckNode?
private let textNode: ASTextNode private let textNode: ASTextNode
public var toggleSelection: (() -> Void)? public var toggleSelection: (() -> Void)?
@ -209,23 +210,20 @@ public final class SelectablePeerNode: ASDisplayNode {
} }
if selected { if selected {
if self.checkView == nil { if self.checkNode == nil {
let checkView = TGCheckButtonView(style: TGCheckButtonStyleShare, pallete: TGCheckButtonPallete(defaultBackgroundColor: self.theme.checkBackgroundColor, accentBackgroundColor: self.theme.checkFillColor, defaultBorderColor: .clear, mediaBorderColor: .clear, chatBorderColor: .clear, check: self.theme.checkColor, blueColor: self.theme.checkFillColor, barBackgroundColor: self.theme.checkBackgroundColor))! let checkNode = CheckNode(theme: CheckNodeTheme(backgroundColor: self.theme.checkFillColor, strokeColor: self.theme.checkColor, borderColor: self.theme.checkBackgroundColor, overlayBorder: true, hasInset: false, hasShadow: false, filledBorder: true, borderWidth: 2.0))
self.checkNode = checkNode
self.checkView = checkView checkNode.isUserInteractionEnabled = false
checkView.isUserInteractionEnabled = false self.addSubnode(checkNode)
self.view.addSubview(checkView)
let avatarFrame = self.avatarNode.frame let avatarFrame = self.avatarNode.frame
let checkSize = checkView.bounds.size let checkSize = CGSize(width: 24.0, height: 24.0)
checkView.frame = CGRect(origin: CGPoint(x: avatarFrame.maxX - 14.0, y: avatarFrame.maxY - 22.0), size: checkSize) checkNode.frame = CGRect(origin: CGPoint(x: avatarFrame.maxX - 10.0, y: avatarFrame.maxY - 18.0), size: checkSize)
checkView.setSelected(true, animated: animated) checkNode.setSelected(true, animated: animated)
} }
} else if let checkView = self.checkView { } else if let checkNode = self.checkNode {
self.checkView = nil self.checkNode = nil
checkView.setSelected(false, animated: animated, bump: false, completion: { [weak checkView] in checkNode.setSelected(false, animated: animated)
checkView?.removeFromSuperview()
})
} }
} }
} }
@ -257,9 +255,9 @@ public final class SelectablePeerNode: ASDisplayNode {
self.onlineNode.frame = CGRect(origin: CGPoint(x: avatarContainerFrame.maxX - self.onlineNode.frame.width - 2.0, y: avatarContainerFrame.maxY - self.onlineNode.frame.height - 2.0), size: self.onlineNode.frame.size) self.onlineNode.frame = CGRect(origin: CGPoint(x: avatarContainerFrame.maxX - self.onlineNode.frame.width - 2.0, y: avatarContainerFrame.maxY - self.onlineNode.frame.height - 2.0), size: self.onlineNode.frame.size)
if let checkView = self.checkView { if let checkNode = self.checkNode {
let checkSize = checkView.bounds.size let checkSize = CGSize(width: 24.0, height: 24.0)
checkView.frame = CGRect(origin: CGPoint(x: avatarFrame.maxX - 14.0, y: avatarFrame.maxY - 22.0), size: checkSize) checkNode.frame = CGRect(origin: CGPoint(x: avatarFrame.maxX - 10.0, y: avatarFrame.maxY - 18.0), size: checkSize)
} }
} }
} }

View File

@ -159,11 +159,11 @@ private enum NotificationPeerExceptionEntry: ItemListNodeEntry {
func item(presentationData: ItemListPresentationData, arguments: Any) -> ListViewItem { func item(presentationData: ItemListPresentationData, arguments: Any) -> ListViewItem {
let arguments = arguments as! NotificationPeerExceptionArguments let arguments = arguments as! NotificationPeerExceptionArguments
switch self { switch self {
case let .remove(_, theme, strings): case let .remove(_, _, strings):
return ItemListActionItem(presentationData: presentationData, title: strings.Notification_Exceptions_RemoveFromExceptions, kind: .generic, alignment: .center, sectionId: self.section, style: .blocks, action: { return ItemListActionItem(presentationData: presentationData, title: strings.Notification_Exceptions_RemoveFromExceptions, kind: .generic, alignment: .center, sectionId: self.section, style: .blocks, action: {
arguments.removeFromExceptions() arguments.removeFromExceptions()
}) })
case let .switcher(_, theme, strings, mode, selected): case let .switcher(_, _, strings, mode, selected):
let title: String let title: String
switch mode { switch mode {
case .alwaysOn: case .alwaysOn:
@ -174,9 +174,9 @@ private enum NotificationPeerExceptionEntry: ItemListNodeEntry {
return ItemListCheckboxItem(presentationData: presentationData, title: title, style: .left, checked: selected, zeroSeparatorInsets: false, sectionId: self.section, action: { return ItemListCheckboxItem(presentationData: presentationData, title: title, style: .left, checked: selected, zeroSeparatorInsets: false, sectionId: self.section, action: {
arguments.selectMode(mode) arguments.selectMode(mode)
}) })
case let .switcherHeader(_, theme, text): case let .switcherHeader(_, _, text):
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section) return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
case let .displayPreviews(_, theme, strings, value, selected): case let .displayPreviews(_, _, strings, value, selected):
let title: String let title: String
switch value { switch value {
case .alwaysOn: case .alwaysOn:
@ -187,21 +187,21 @@ private enum NotificationPeerExceptionEntry: ItemListNodeEntry {
return ItemListCheckboxItem(presentationData: presentationData, title: title, style: .left, checked: selected, zeroSeparatorInsets: false, sectionId: self.section, action: { return ItemListCheckboxItem(presentationData: presentationData, title: title, style: .left, checked: selected, zeroSeparatorInsets: false, sectionId: self.section, action: {
arguments.selectDisplayPreviews(value) arguments.selectDisplayPreviews(value)
}) })
case let .displayPreviewsHeader(_, theme, text): case let .displayPreviewsHeader(_, _, text):
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section) return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
case let .soundModernHeader(_, theme, text): case let .soundModernHeader(_, _, text):
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section) return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
case let .soundClassicHeader(_, theme, text): case let .soundClassicHeader(_, _, text):
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section) return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
case let .none(_, _, theme, text, selected): case let .none(_, _, _, text, selected):
return ItemListCheckboxItem(presentationData: presentationData, title: text, style: .left, checked: selected, zeroSeparatorInsets: true, sectionId: self.section, action: { return ItemListCheckboxItem(presentationData: presentationData, title: text, style: .left, checked: selected, zeroSeparatorInsets: true, sectionId: self.section, action: {
arguments.selectSound(.none) arguments.selectSound(.none)
}) })
case let .default(_, _, theme, text, selected): case let .default(_, _, _, text, selected):
return ItemListCheckboxItem(presentationData: presentationData, title: text, style: .left, checked: selected, zeroSeparatorInsets: false, sectionId: self.section, action: { return ItemListCheckboxItem(presentationData: presentationData, title: text, style: .left, checked: selected, zeroSeparatorInsets: false, sectionId: self.section, action: {
arguments.selectSound(.default) arguments.selectSound(.default)
}) })
case let .sound(_, _, theme, text, sound, selected): case let .sound(_, _, _, text, sound, selected):
return ItemListCheckboxItem(presentationData: presentationData, title: text, style: .left, checked: selected, zeroSeparatorInsets: false, sectionId: self.section, action: { return ItemListCheckboxItem(presentationData: presentationData, title: text, style: .left, checked: selected, zeroSeparatorInsets: false, sectionId: self.section, action: {
arguments.selectSound(sound) arguments.selectSound(sound)
}) })

View File

@ -13,7 +13,7 @@ enum WallpaperOptionButtonValue {
final class WallpaperOptionButtonNode: HighlightTrackingButtonNode { final class WallpaperOptionButtonNode: HighlightTrackingButtonNode {
private let backgroundNode: ASDisplayNode private let backgroundNode: ASDisplayNode
private let checkNode: ModernCheckNode private let checkNode: CheckNode
private let colorNode: ASImageNode private let colorNode: ASImageNode
private let textNode: ASTextNode private let textNode: ASTextNode
@ -45,7 +45,7 @@ final class WallpaperOptionButtonNode: HighlightTrackingButtonNode {
self.backgroundNode.backgroundColor = UIColor(rgb: 0x000000, alpha: 0.3) self.backgroundNode.backgroundColor = UIColor(rgb: 0x000000, alpha: 0.3)
self.backgroundNode.cornerRadius = 14.0 self.backgroundNode.cornerRadius = 14.0
self.checkNode = ModernCheckNode(theme: CheckNodeTheme(backgroundColor: .white, strokeColor: .clear, borderColor: .white, hasShadow: false)) self.checkNode = CheckNode(theme: CheckNodeTheme(backgroundColor: .white, strokeColor: .clear, borderColor: .white, overlayBorder: false, hasInset: false, hasShadow: false, borderWidth: 1.5))
self.checkNode.isUserInteractionEnabled = false self.checkNode.isUserInteractionEnabled = false
self.colorNode = ASImageNode() self.colorNode = ASImageNode()

View File

@ -94,13 +94,13 @@ public extension ActionSheetController {
public extension AlertControllerTheme { public extension AlertControllerTheme {
convenience init(presentationTheme: PresentationTheme, fontSize: PresentationFontSize) { convenience init(presentationTheme: PresentationTheme, fontSize: PresentationFontSize) {
let actionSheet = presentationTheme.actionSheet let actionSheet = presentationTheme.actionSheet
self.init(backgroundType: actionSheet.backgroundType == .light ? .light : .dark, backgroundColor: actionSheet.itemBackgroundColor, separatorColor: actionSheet.itemHighlightedBackgroundColor, highlightedItemColor: actionSheet.itemHighlightedBackgroundColor, primaryColor: actionSheet.primaryTextColor, secondaryColor: actionSheet.secondaryTextColor, accentColor: actionSheet.controlAccentColor, destructiveColor: actionSheet.destructiveActionTextColor, disabledColor: actionSheet.disabledActionTextColor, baseFontSize: fontSize.baseDisplaySize) self.init(backgroundType: actionSheet.backgroundType == .light ? .light : .dark, backgroundColor: actionSheet.itemBackgroundColor, separatorColor: actionSheet.itemHighlightedBackgroundColor, highlightedItemColor: actionSheet.itemHighlightedBackgroundColor, primaryColor: actionSheet.primaryTextColor, secondaryColor: actionSheet.secondaryTextColor, accentColor: actionSheet.controlAccentColor, contrastColor: presentationTheme.list.itemCheckColors.foregroundColor, destructiveColor: actionSheet.destructiveActionTextColor, disabledColor: actionSheet.disabledActionTextColor, controlBorderColor: presentationTheme.list.itemCheckColors.strokeColor, baseFontSize: fontSize.baseDisplaySize)
} }
convenience init(presentationData: PresentationData) { convenience init(presentationData: PresentationData) {
let presentationTheme = presentationData.theme let presentationTheme = presentationData.theme
let actionSheet = presentationTheme.actionSheet let actionSheet = presentationTheme.actionSheet
self.init(backgroundType: actionSheet.backgroundType == .light ? .light : .dark, backgroundColor: actionSheet.itemBackgroundColor, separatorColor: actionSheet.itemHighlightedBackgroundColor, highlightedItemColor: actionSheet.itemHighlightedBackgroundColor, primaryColor: actionSheet.primaryTextColor, secondaryColor: actionSheet.secondaryTextColor, accentColor: actionSheet.controlAccentColor, destructiveColor: actionSheet.destructiveActionTextColor, disabledColor: actionSheet.disabledActionTextColor, baseFontSize: presentationData.listsFontSize.baseDisplaySize) self.init(backgroundType: actionSheet.backgroundType == .light ? .light : .dark, backgroundColor: actionSheet.itemBackgroundColor, separatorColor: actionSheet.itemHighlightedBackgroundColor, highlightedItemColor: actionSheet.itemHighlightedBackgroundColor, primaryColor: actionSheet.primaryTextColor, secondaryColor: actionSheet.secondaryTextColor, accentColor: actionSheet.controlAccentColor, contrastColor: presentationData.theme.list.itemCheckColors.foregroundColor, destructiveColor: actionSheet.destructiveActionTextColor, disabledColor: actionSheet.disabledActionTextColor, controlBorderColor: presentationData.theme.list.itemCheckColors.strokeColor, baseFontSize: presentationData.listsFontSize.baseDisplaySize)
} }
} }

View File

@ -30,9 +30,9 @@ private final class ChatMessageActionUrlAuthAlertContentNode: AlertContentNode {
private let titleNode: ASTextNode private let titleNode: ASTextNode
private let textNode: ASTextNode private let textNode: ASTextNode
private let authorizeCheckNode: CheckNode private let authorizeCheckNode: InteractiveCheckNode
private let authorizeLabelNode: ASTextNode private let authorizeLabelNode: ASTextNode
private let allowWriteCheckNode: CheckNode private let allowWriteCheckNode: InteractiveCheckNode
private let allowWriteLabelNode: ASTextNode private let allowWriteLabelNode: ASTextNode
private let actionNodesSeparator: ASDisplayNode private let actionNodesSeparator: ASDisplayNode
@ -47,7 +47,7 @@ private final class ChatMessageActionUrlAuthAlertContentNode: AlertContentNode {
var authorize: Bool = true { var authorize: Bool = true {
didSet { didSet {
self.authorizeCheckNode.setIsChecked(self.authorize, animated: true) self.authorizeCheckNode.setSelected(self.authorize, animated: true)
self.allowWriteCheckNode.isUserInteractionEnabled = self.authorize self.allowWriteCheckNode.isUserInteractionEnabled = self.authorize
self.allowWriteCheckNode.alpha = self.authorize ? 1.0 : 0.4 self.allowWriteCheckNode.alpha = self.authorize ? 1.0 : 0.4
self.allowWriteLabelNode.alpha = self.authorize ? 1.0 : 0.4 self.allowWriteLabelNode.alpha = self.authorize ? 1.0 : 0.4
@ -59,7 +59,7 @@ private final class ChatMessageActionUrlAuthAlertContentNode: AlertContentNode {
var allowWriteAccess: Bool = true { var allowWriteAccess: Bool = true {
didSet { didSet {
self.allowWriteCheckNode.setIsChecked(self.allowWriteAccess, animated: true) self.allowWriteCheckNode.setSelected(self.allowWriteAccess, animated: true)
} }
} }
@ -77,14 +77,14 @@ private final class ChatMessageActionUrlAuthAlertContentNode: AlertContentNode {
self.textNode = ASTextNode() self.textNode = ASTextNode()
self.textNode.maximumNumberOfLines = 0 self.textNode.maximumNumberOfLines = 0
self.authorizeCheckNode = CheckNode(strokeColor: theme.separatorColor, fillColor: theme.accentColor, foregroundColor: .white, style: .plain) self.authorizeCheckNode = InteractiveCheckNode(theme: CheckNodeTheme(backgroundColor: theme.accentColor, strokeColor: theme.contrastColor, borderColor: theme.controlBorderColor, overlayBorder: false, hasInset: false, hasShadow: false))
self.authorizeCheckNode.setIsChecked(true, animated: false) self.authorizeCheckNode.setSelected(true, animated: false)
self.authorizeLabelNode = ASTextNode() self.authorizeLabelNode = ASTextNode()
self.authorizeLabelNode.maximumNumberOfLines = 4 self.authorizeLabelNode.maximumNumberOfLines = 4
self.authorizeLabelNode.isUserInteractionEnabled = true self.authorizeLabelNode.isUserInteractionEnabled = true
self.allowWriteCheckNode = CheckNode(strokeColor: theme.separatorColor, fillColor: theme.accentColor, foregroundColor: .white, style: .plain) self.allowWriteCheckNode = InteractiveCheckNode(theme: CheckNodeTheme(backgroundColor: theme.accentColor, strokeColor: theme.contrastColor, borderColor: theme.controlBorderColor, overlayBorder: false, hasInset: false, hasShadow: false))
self.allowWriteCheckNode.setIsChecked(true, animated: false) self.allowWriteCheckNode.setSelected(true, animated: false)
self.allowWriteLabelNode = ASTextNode() self.allowWriteLabelNode = ASTextNode()
self.allowWriteLabelNode.maximumNumberOfLines = 4 self.allowWriteLabelNode.maximumNumberOfLines = 4
self.allowWriteLabelNode.isUserInteractionEnabled = true self.allowWriteLabelNode.isUserInteractionEnabled = true
@ -128,8 +128,16 @@ private final class ChatMessageActionUrlAuthAlertContentNode: AlertContentNode {
self.addSubnode(separatorNode) self.addSubnode(separatorNode)
} }
self.authorizeCheckNode.addTarget(target: self, action: #selector(self.authorizePressed)) self.authorizeCheckNode.valueChanged = { [weak self] value in
self.allowWriteCheckNode.addTarget(target: self, action: #selector(self.allowWritePressed)) if let strongSelf = self {
strongSelf.authorize = !strongSelf.authorize
}
}
self.allowWriteCheckNode.valueChanged = { [weak self] value in
if let strongSelf = self {
strongSelf.allowWriteAccess = !strongSelf.allowWriteAccess
}
}
self.updateTheme(theme) self.updateTheme(theme)
} }
@ -141,10 +149,6 @@ private final class ChatMessageActionUrlAuthAlertContentNode: AlertContentNode {
self.allowWriteLabelNode.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.allowWriteTap(_:)))) self.allowWriteLabelNode.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.allowWriteTap(_:))))
} }
@objc private func authorizePressed() {
self.authorize = !self.authorize
}
@objc private func authorizeTap(_ gestureRecognizer: UITapGestureRecognizer) { @objc private func authorizeTap(_ gestureRecognizer: UITapGestureRecognizer) {
self.authorize = !self.authorize self.authorize = !self.authorize
} }
@ -155,10 +159,6 @@ private final class ChatMessageActionUrlAuthAlertContentNode: AlertContentNode {
} }
} }
@objc private func allowWritePressed() {
self.allowWriteAccess = !self.allowWriteAccess
}
override func updateTheme(_ theme: AlertControllerTheme) { override func updateTheme(_ theme: AlertControllerTheme) {
self.titleNode.attributedText = NSAttributedString(string: strings.Conversation_OpenBotLinkTitle, font: Font.bold(17.0), textColor: theme.primaryColor, paragraphAlignment: .center) self.titleNode.attributedText = NSAttributedString(string: strings.Conversation_OpenBotLinkTitle, font: Font.bold(17.0), textColor: theme.primaryColor, paragraphAlignment: .center)
@ -196,14 +196,14 @@ private final class ChatMessageActionUrlAuthAlertContentNode: AlertContentNode {
transition.updateFrame(node: self.textNode, frame: CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - textSize.width) / 2.0), y: origin.y), size: textSize)) transition.updateFrame(node: self.textNode, frame: CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - textSize.width) / 2.0), y: origin.y), size: textSize))
origin.y += textSize.height + 16.0 origin.y += textSize.height + 16.0
let checkSize = CGSize(width: 32.0, height: 32.0) let checkSize = CGSize(width: 22.0, height: 22.0)
let condensedSize = CGSize(width: size.width - 76.0, height: size.height) let condensedSize = CGSize(width: size.width - 76.0, height: size.height)
var entriesHeight: CGFloat = 0.0 var entriesHeight: CGFloat = 0.0
let authorizeSize = self.authorizeLabelNode.measure(condensedSize) let authorizeSize = self.authorizeLabelNode.measure(condensedSize)
transition.updateFrame(node: self.authorizeLabelNode, frame: CGRect(origin: CGPoint(x: 46.0, y: origin.y), size: authorizeSize)) transition.updateFrame(node: self.authorizeLabelNode, frame: CGRect(origin: CGPoint(x: 46.0, y: origin.y), size: authorizeSize))
transition.updateFrame(node: self.authorizeCheckNode, frame: CGRect(origin: CGPoint(x: 7.0, y: origin.y - 7.0), size: checkSize)) transition.updateFrame(node: self.authorizeCheckNode, frame: CGRect(origin: CGPoint(x: 12.0, y: origin.y - 2.0), size: checkSize))
origin.y += authorizeSize.height origin.y += authorizeSize.height
entriesHeight += authorizeSize.height entriesHeight += authorizeSize.height
@ -213,7 +213,7 @@ private final class ChatMessageActionUrlAuthAlertContentNode: AlertContentNode {
let allowWriteSize = self.allowWriteLabelNode.measure(condensedSize) let allowWriteSize = self.allowWriteLabelNode.measure(condensedSize)
transition.updateFrame(node: self.allowWriteLabelNode, frame: CGRect(origin: CGPoint(x: 46.0, y: origin.y), size: allowWriteSize)) transition.updateFrame(node: self.allowWriteLabelNode, frame: CGRect(origin: CGPoint(x: 46.0, y: origin.y), size: allowWriteSize))
transition.updateFrame(node: self.allowWriteCheckNode, frame: CGRect(origin: CGPoint(x: 7.0, y: origin.y - 7.0), size: checkSize)) transition.updateFrame(node: self.allowWriteCheckNode, frame: CGRect(origin: CGPoint(x: 12.0, y: origin.y - 2.0), size: checkSize))
origin.y += allowWriteSize.height origin.y += allowWriteSize.height
entriesHeight += allowWriteSize.height entriesHeight += allowWriteSize.height
} }

View File

@ -1128,7 +1128,7 @@ final class FileMessageSelectionNode: ASDisplayNode {
public init(theme: PresentationTheme, incoming: Bool, noPreview: Bool, toggle: @escaping (Bool) -> Void) { public init(theme: PresentationTheme, incoming: Bool, noPreview: Bool, toggle: @escaping (Bool) -> Void) {
self.noPreview = noPreview self.noPreview = noPreview
self.toggle = toggle self.toggle = toggle
self.checkNode = CheckNode(strokeColor: incoming ? theme.chat.message.incoming.mediaPlaceholderColor : theme.chat.message.outgoing.mediaPlaceholderColor, fillColor: theme.list.itemCheckColors.fillColor, foregroundColor: theme.list.itemCheckColors.foregroundColor, style: noPreview ? .compact : .overlay) self.checkNode = CheckNode(theme: noPreview ? CheckNodeTheme(backgroundColor: theme.list.itemCheckColors.fillColor, strokeColor: theme.list.itemCheckColors.foregroundColor, borderColor: incoming ? theme.chat.message.incoming.mediaPlaceholderColor : theme.chat.message.outgoing.mediaPlaceholderColor, overlayBorder: false, hasInset: false, hasShadow: false) : CheckNodeTheme(theme: theme, style: .overlay))
self.checkNode.isUserInteractionEnabled = false self.checkNode.isUserInteractionEnabled = false
super.init() super.init()
@ -1157,7 +1157,7 @@ final class FileMessageSelectionNode: ASDisplayNode {
public func updateSelected(_ selected: Bool, animated: Bool) { public func updateSelected(_ selected: Bool, animated: Bool) {
if self.selected != selected { if self.selected != selected {
self.selected = selected self.selected = selected
self.checkNode.setIsChecked(selected, animated: animated) self.checkNode.setSelected(selected, animated: animated)
} }
} }
@ -1170,12 +1170,14 @@ final class FileMessageSelectionNode: ASDisplayNode {
override public func layout() { override public func layout() {
super.layout() super.layout()
let checkSize = CGSize(width: 30.0, height: 30.0) let checkSize: CGSize
let checkOrigin: CGPoint let checkOrigin: CGPoint
if self.noPreview { if self.noPreview {
checkOrigin = CGPoint(x: 23.0, y: 20.0) checkSize = CGSize(width: 20.0, height: 20.0)
checkOrigin = CGPoint(x: 29.0, y: 26.0)
} else { } else {
checkOrigin = CGPoint(x: 39.0, y: -5.0) checkSize = CGSize(width: 28.0, height: 28.0)
checkOrigin = CGPoint(x: 41.0, y: -3.0)
} }
self.checkNode.frame = CGRect(origin: checkOrigin, size: checkSize) self.checkNode.frame = CGRect(origin: checkOrigin, size: checkSize)
} }

View File

@ -14,21 +14,19 @@ final class ChatMessageSelectionNode: ASDisplayNode {
init(wallpaper: TelegramWallpaper, theme: PresentationTheme, toggle: @escaping (Bool) -> Void) { init(wallpaper: TelegramWallpaper, theme: PresentationTheme, toggle: @escaping (Bool) -> Void) {
self.toggle = toggle self.toggle = toggle
let style: CheckNodeStyle let style: CheckNodeTheme.Style
if wallpaper == theme.chat.defaultWallpaper, case .color = wallpaper { if wallpaper == theme.chat.defaultWallpaper, case .color = wallpaper {
style = .plain style = .plain
} else { } else {
style = .overlay style = .overlay
} }
self.checkNode = CheckNode(strokeColor: theme.list.itemCheckColors.strokeColor, fillColor: theme.list.itemCheckColors.fillColor, foregroundColor: theme.list.itemCheckColors.foregroundColor, style: style) self.checkNode = CheckNode(theme: CheckNodeTheme(theme: theme, style: style, hasInset: true))
self.checkNode.isUserInteractionEnabled = false self.checkNode.isUserInteractionEnabled = false
super.init() super.init()
self.addSubnode(self.checkNode) self.addSubnode(self.checkNode)
//self.hitTestSlop = UIEdgeInsetsMake(0.0, 42.0, 0.0, 0.0)
} }
override func didLoad() { override func didLoad() {
@ -40,7 +38,7 @@ final class ChatMessageSelectionNode: ASDisplayNode {
func updateSelected(_ selected: Bool, animated: Bool) { func updateSelected(_ selected: Bool, animated: Bool) {
if self.selected != selected { if self.selected != selected {
self.selected = selected self.selected = selected
self.checkNode.setIsChecked(selected, animated: animated) self.checkNode.setSelected(selected, animated: animated)
} }
} }
@ -51,7 +49,7 @@ final class ChatMessageSelectionNode: ASDisplayNode {
} }
func updateLayout(size: CGSize, leftInset: CGFloat) { func updateLayout(size: CGSize, leftInset: CGFloat) {
let checkSize = CGSize(width: 32.0, height: 32.0) let checkSize = CGSize(width: 28.0, height: 28.0)
self.checkNode.frame = CGRect(origin: CGPoint(x: 4.0 + leftInset, y: floor((size.height - checkSize.height) / 2.0)), size: checkSize) self.checkNode.frame = CGRect(origin: CGPoint(x: 6.0 + leftInset, y: floor((size.height - checkSize.height) / 2.0)), size: checkSize)
} }
} }

View File

@ -178,7 +178,6 @@ class WebSearchGalleryController: ViewController {
if let checkNode = self.checkNode, let controllerInteraction = self.controllerInteraction, let centralItemNode = self.galleryNode.pager.centralItemNode() as? WebSearchVideoGalleryItemNode, let item = centralItemNode.item { if let checkNode = self.checkNode, let controllerInteraction = self.controllerInteraction, let centralItemNode = self.galleryNode.pager.centralItemNode() as? WebSearchVideoGalleryItemNode, let item = centralItemNode.item {
let legacyItem = LegacyWebSearchItem(result: item.result) let legacyItem = LegacyWebSearchItem(result: item.result)
checkNode.setIsChecked(!checkNode.isChecked, animated: true)
controllerInteraction.selectionState?.setItem(legacyItem, selected: checkNode.isChecked) controllerInteraction.selectionState?.setItem(legacyItem, selected: checkNode.isChecked)
} }
} }

View File

@ -210,17 +210,12 @@ final class WebSearchItemNode: GridItemNode {
self.updateSelectionState(animated: false) self.updateSelectionState(animated: false)
} }
@objc func toggleSelection() {
if let checkNode = self.checkNode, let item = self.item {
checkNode.setIsChecked(!checkNode.isChecked, animated: true)
item.controllerInteraction.toggleSelection(item.result, checkNode.isChecked)
}
}
func updateSelectionState(animated: Bool) { func updateSelectionState(animated: Bool) {
if self.checkNode == nil, let item = self.item, let _ = item.controllerInteraction.selectionState { if self.checkNode == nil, let item = self.item, let _ = item.controllerInteraction.selectionState {
let checkNode = CheckNode(strokeColor: item.theme.list.itemCheckColors.strokeColor, fillColor: item.theme.list.itemCheckColors.fillColor, foregroundColor: item.theme.list.itemCheckColors.foregroundColor, style: .overlay) let checkNode = InteractiveCheckNode(theme: CheckNodeTheme(theme: item.theme, style: .overlay))
checkNode.addTarget(target: self, action: #selector(self.toggleSelection)) checkNode.valueChanged = { value in
item.controllerInteraction.toggleSelection(item.result, value)
}
self.addSubnode(checkNode) self.addSubnode(checkNode)
self.checkNode = checkNode self.checkNode = checkNode
self.setNeedsLayout() self.setNeedsLayout()
@ -229,7 +224,7 @@ final class WebSearchItemNode: GridItemNode {
if let item = self.item { if let item = self.item {
if let selectionState = item.controllerInteraction.selectionState { if let selectionState = item.controllerInteraction.selectionState {
let selected = selectionState.isIdentifierSelected(item.result.id) let selected = selectionState.isIdentifierSelected(item.result.id)
self.checkNode?.setIsChecked(selected, animated: animated) self.checkNode?.setSelected(selected, animated: animated)
} }
} }
} }
@ -261,8 +256,8 @@ final class WebSearchItemNode: GridItemNode {
self.imageNode.asyncLayout()(TransformImageArguments(corners: ImageCorners(), imageSize: imageSize, boundingSize: imageFrame.size, intrinsicInsets: UIEdgeInsets(), emptyColor: item.theme.list.mediaPlaceholderColor))() self.imageNode.asyncLayout()(TransformImageArguments(corners: ImageCorners(), imageSize: imageSize, boundingSize: imageFrame.size, intrinsicInsets: UIEdgeInsets(), emptyColor: item.theme.list.mediaPlaceholderColor))()
} }
let checkSize = CGSize(width: 32.0, height: 32.0) let checkSize = CGSize(width: 28.0, height: 28.0)
self.checkNode?.frame = CGRect(origin: CGPoint(x: imageFrame.width - checkSize.width, y: 0.0), size: checkSize) self.checkNode?.frame = CGRect(origin: CGPoint(x: imageFrame.width - checkSize.width - 2.0, y: 2.0), size: checkSize)
} }
@objc func tapLongTapOrDoubleTapGesture(_ recognizer: TapLongTapOrDoubleTapGestureRecognizer) { @objc func tapLongTapOrDoubleTapGesture(_ recognizer: TapLongTapOrDoubleTapGestureRecognizer) {