mirror of
https://github.com/TelegramMessenger/Telegram-iOS.git
synced 2026-07-06 03:33:41 +02:00
Peer info button improvements
This commit is contained in:
parent
492a91377a
commit
9f478456d7
5 changed files with 203 additions and 12 deletions
|
|
@ -1573,6 +1573,56 @@ public extension ContainedViewLayoutTransition {
|
|||
}
|
||||
}
|
||||
|
||||
func updateLineWidth(layer: CAShapeLayer, lineWidth: CGFloat, delay: Double = 0.0, completion: ((Bool) -> Void)? = nil) {
|
||||
if layer.lineWidth == lineWidth {
|
||||
completion?(true)
|
||||
return
|
||||
}
|
||||
|
||||
switch self {
|
||||
case .immediate:
|
||||
layer.removeAnimation(forKey: "lineWidth")
|
||||
layer.lineWidth = lineWidth
|
||||
if let completion = completion {
|
||||
completion(true)
|
||||
}
|
||||
case let .animated(duration, curve):
|
||||
let fromLineWidth = layer.lineWidth
|
||||
layer.lineWidth = lineWidth
|
||||
layer.animate(from: fromLineWidth as NSNumber, to: lineWidth as NSNumber, keyPath: "lineWidth", timingFunction: curve.timingFunction, duration: duration, delay: delay, mediaTimingFunction: curve.mediaTimingFunction, removeOnCompletion: true, additive: false, completion: {
|
||||
result in
|
||||
if let completion = completion {
|
||||
completion(result)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func updateStrokeColor(layer: CAShapeLayer, strokeColor: UIColor, delay: Double = 0.0, completion: ((Bool) -> Void)? = nil) {
|
||||
if layer.strokeColor.flatMap(UIColor.init(cgColor:)) == strokeColor {
|
||||
completion?(true)
|
||||
return
|
||||
}
|
||||
|
||||
switch self {
|
||||
case .immediate:
|
||||
layer.removeAnimation(forKey: "strokeColor")
|
||||
layer.strokeColor = strokeColor.cgColor
|
||||
if let completion = completion {
|
||||
completion(true)
|
||||
}
|
||||
case let .animated(duration, curve):
|
||||
let fromStrokeColor = layer.strokeColor ?? UIColor.clear.cgColor
|
||||
layer.strokeColor = strokeColor.cgColor
|
||||
layer.animate(from: fromStrokeColor, to: strokeColor.cgColor, keyPath: "strokeColor", timingFunction: curve.timingFunction, duration: duration, delay: delay, mediaTimingFunction: curve.mediaTimingFunction, removeOnCompletion: true, additive: false, completion: {
|
||||
result in
|
||||
if let completion = completion {
|
||||
completion(result)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func attachAnimation(view: UIView, id: String, completion: @escaping (Bool) -> Void) {
|
||||
switch self {
|
||||
case .immediate:
|
||||
|
|
|
|||
|
|
@ -925,3 +925,68 @@ public func drawSvgPath(_ context: CGContext, path: StaticString, strokeOnMove:
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func convertSvgPath(_ path: StaticString) throws -> CGPath {
|
||||
var index: UnsafePointer<UInt8> = path.utf8Start
|
||||
let end = path.utf8Start.advanced(by: path.utf8CodeUnitCount)
|
||||
var currentPoint = CGPoint()
|
||||
|
||||
let result = CGMutablePath()
|
||||
|
||||
while index < end {
|
||||
let c = index.pointee
|
||||
index = index.successor()
|
||||
|
||||
if c == 77 { // M
|
||||
let x = try readCGFloat(&index, end: end, separator: 44)
|
||||
let y = try readCGFloat(&index, end: end, separator: 32)
|
||||
|
||||
//print("Move to \(x), \(y)")
|
||||
currentPoint = CGPoint(x: x, y: y)
|
||||
result.move(to: currentPoint)
|
||||
} else if c == 76 { // L
|
||||
let x = try readCGFloat(&index, end: end, separator: 44)
|
||||
let y = try readCGFloat(&index, end: end, separator: 32)
|
||||
|
||||
//print("Line to \(x), \(y)")
|
||||
currentPoint = CGPoint(x: x, y: y)
|
||||
result.addLine(to: currentPoint)
|
||||
} else if c == 72 { // H
|
||||
let x = try readCGFloat(&index, end: end, separator: 32)
|
||||
|
||||
//print("Move to \(x), \(y)")
|
||||
currentPoint = CGPoint(x: x, y: currentPoint.y)
|
||||
result.addLine(to: currentPoint)
|
||||
} else if c == 86 { // V
|
||||
let y = try readCGFloat(&index, end: end, separator: 32)
|
||||
|
||||
//print("Move to \(x), \(y)")
|
||||
currentPoint = CGPoint(x: currentPoint.x, y: y)
|
||||
result.addLine(to: currentPoint)
|
||||
} else if c == 67 { // C
|
||||
let x1 = try readCGFloat(&index, end: end, separator: 44)
|
||||
let y1 = try readCGFloat(&index, end: end, separator: 32)
|
||||
let x2 = try readCGFloat(&index, end: end, separator: 44)
|
||||
let y2 = try readCGFloat(&index, end: end, separator: 32)
|
||||
let x = try readCGFloat(&index, end: end, separator: 44)
|
||||
let y = try readCGFloat(&index, end: end, separator: 32)
|
||||
|
||||
currentPoint = CGPoint(x: x, y: y)
|
||||
result.addCurve(to: currentPoint, control1: CGPoint(x: x1, y: y1), control2: CGPoint(x: x2, y: y2))
|
||||
} else if c == 90 { // Z
|
||||
if index != end && index.pointee != 32 {
|
||||
throw ParsingError.Generic
|
||||
}
|
||||
} else if c == 83 { // S
|
||||
if index != end && index.pointee != 32 {
|
||||
throw ParsingError.Generic
|
||||
}
|
||||
} else if c == 32 { // space
|
||||
continue
|
||||
} else {
|
||||
throw ParsingError.Generic
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
|
|
|||
|
|
@ -97,6 +97,7 @@ final class PeerInfoHeaderNavigationButton: HighlightableButtonNode {
|
|||
let contextSourceNode: ContextReferenceContentNode
|
||||
private let textNode: ImmediateTextNode
|
||||
private let iconNode: ASImageNode
|
||||
private let backIconLayer: SimpleShapeLayer
|
||||
private var animationNode: MoreIconNode?
|
||||
private let backgroundNode: NavigationBackgroundNode
|
||||
|
||||
|
|
@ -117,6 +118,15 @@ final class PeerInfoHeaderNavigationButton: HighlightableButtonNode {
|
|||
self.iconNode.displaysAsynchronously = false
|
||||
self.iconNode.displayWithoutProcessing = true
|
||||
|
||||
self.backIconLayer = SimpleShapeLayer()
|
||||
self.backIconLayer.lineWidth = 3.0
|
||||
self.backIconLayer.lineCap = .round
|
||||
self.backIconLayer.lineJoin = .round
|
||||
self.backIconLayer.strokeColor = UIColor.white.cgColor
|
||||
self.backIconLayer.fillColor = nil
|
||||
self.backIconLayer.isHidden = true
|
||||
self.backIconLayer.path = try? convertSvgPath("M10.5,2 L1.5,11 L10.5,20 ")
|
||||
|
||||
self.backgroundNode = NavigationBackgroundNode(color: .clear, enableBlur: true)
|
||||
|
||||
super.init(pointerStyle: .insetRectangle(-8.0, 2.0))
|
||||
|
|
@ -128,6 +138,7 @@ final class PeerInfoHeaderNavigationButton: HighlightableButtonNode {
|
|||
self.contextSourceNode.addSubnode(self.backgroundNode)
|
||||
self.contextSourceNode.addSubnode(self.textNode)
|
||||
self.contextSourceNode.addSubnode(self.iconNode)
|
||||
self.contextSourceNode.layer.addSublayer(self.backIconLayer)
|
||||
|
||||
self.addSubnode(self.containerNode)
|
||||
|
||||
|
|
@ -146,13 +157,43 @@ final class PeerInfoHeaderNavigationButton: HighlightableButtonNode {
|
|||
self.action?(self.contextSourceNode, nil)
|
||||
}
|
||||
|
||||
func updateContentsColor(backgroundColor: UIColor, contentsColor: UIColor, transition: ContainedViewLayoutTransition) {
|
||||
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
||||
var boundingRect = self.bounds
|
||||
if self.textNode.alpha != 0.0 {
|
||||
boundingRect = boundingRect.union(self.textNode.frame)
|
||||
}
|
||||
boundingRect = boundingRect.insetBy(dx: -8.0, dy: -4.0)
|
||||
if boundingRect.contains(point) {
|
||||
return super.hitTest(self.bounds.center, with: event)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func updateContentsColor(backgroundColor: UIColor, contentsColor: UIColor, canBeExpanded: Bool, transition: ContainedViewLayoutTransition) {
|
||||
self.contentsColor = contentsColor
|
||||
|
||||
self.backgroundNode.updateColor(color: backgroundColor, transition: transition)
|
||||
|
||||
transition.updateTintColor(layer: self.textNode.layer, color: self.contentsColor)
|
||||
transition.updateTintColor(layer: self.iconNode.layer, color: self.contentsColor)
|
||||
transition.updateStrokeColor(layer: self.backIconLayer, strokeColor: self.contentsColor)
|
||||
|
||||
switch self.key {
|
||||
case .back:
|
||||
transition.updateAlpha(layer: self.textNode.layer, alpha: canBeExpanded ? 1.0 : 0.0)
|
||||
transition.updateTransformScale(node: self.textNode, scale: canBeExpanded ? 1.0 : 0.001)
|
||||
|
||||
var iconTransform = CATransform3DIdentity
|
||||
iconTransform = CATransform3DScale(iconTransform, canBeExpanded ? 1.0 : 0.8, canBeExpanded ? 1.0 : 0.8, 1.0)
|
||||
iconTransform = CATransform3DTranslate(iconTransform, canBeExpanded ? -7.0 : 0.0, 0.0, 0.0)
|
||||
transition.updateTransform(node: self.iconNode, transform: CATransform3DGetAffineTransform(iconTransform))
|
||||
|
||||
transition.updateTransform(layer: self.backIconLayer, transform: CATransform3DGetAffineTransform(iconTransform))
|
||||
transition.updateLineWidth(layer: self.backIconLayer, lineWidth: canBeExpanded ? 3.0 : 2.075)
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
if let animationNode = self.animationNode {
|
||||
transition.updateTintColor(layer: animationNode.imageNode.layer, color: self.contentsColor)
|
||||
|
|
@ -184,9 +225,9 @@ final class PeerInfoHeaderNavigationButton: HighlightableButtonNode {
|
|||
var animationState: MoreIconNodeState = .more
|
||||
switch key {
|
||||
case .back:
|
||||
text = ""
|
||||
text = presentationData.strings.Common_Back
|
||||
accessibilityText = presentationData.strings.Common_Back
|
||||
icon = NavigationBar.thinBackArrowImage
|
||||
icon = NavigationBar.backArrowImage(color: .white)
|
||||
case .edit:
|
||||
text = presentationData.strings.Common_Edit
|
||||
accessibilityText = text
|
||||
|
|
@ -270,11 +311,19 @@ final class PeerInfoHeaderNavigationButton: HighlightableButtonNode {
|
|||
}
|
||||
|
||||
let inset: CGFloat = 0.0
|
||||
var textInset: CGFloat = 0.0
|
||||
switch key {
|
||||
case .back:
|
||||
textInset += 11.0
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
let resultSize: CGSize
|
||||
|
||||
let textFrame = CGRect(origin: CGPoint(x: inset, y: floor((height - textSize.height) / 2.0)), size: textSize)
|
||||
self.textNode.frame = textFrame
|
||||
let textFrame = CGRect(origin: CGPoint(x: inset + textInset, y: floor((height - textSize.height) / 2.0)), size: textSize)
|
||||
self.textNode.position = textFrame.center
|
||||
self.textNode.bounds = CGRect(origin: CGPoint(), size: textFrame.size)
|
||||
|
||||
if let animationNode = self.animationNode {
|
||||
let animationSize = CGSize(width: 30.0, height: 30.0)
|
||||
|
|
@ -286,7 +335,20 @@ final class PeerInfoHeaderNavigationButton: HighlightableButtonNode {
|
|||
self.contextSourceNode.frame = CGRect(origin: CGPoint(), size: size)
|
||||
resultSize = size
|
||||
} else if let image = self.iconNode.image {
|
||||
self.iconNode.frame = CGRect(origin: CGPoint(x: inset, y: floor((height - image.size.height) / 2.0)), size: image.size).offsetBy(dx: iconOffset.x, dy: iconOffset.y)
|
||||
let iconFrame = CGRect(origin: CGPoint(x: inset, y: floor((height - image.size.height) / 2.0)), size: image.size).offsetBy(dx: iconOffset.x, dy: iconOffset.y)
|
||||
self.iconNode.position = iconFrame.center
|
||||
self.iconNode.bounds = CGRect(origin: CGPoint(), size: iconFrame.size)
|
||||
|
||||
if case .back = key {
|
||||
self.backIconLayer.position = iconFrame.center
|
||||
self.backIconLayer.bounds = CGRect(origin: CGPoint(), size: iconFrame.size)
|
||||
|
||||
self.iconNode.isHidden = true
|
||||
self.backIconLayer.isHidden = false
|
||||
} else {
|
||||
self.iconNode.isHidden = false
|
||||
self.backIconLayer.isHidden = true
|
||||
}
|
||||
|
||||
let size = CGSize(width: image.size.width + inset * 2.0, height: height)
|
||||
self.containerNode.frame = CGRect(origin: CGPoint(), size: size)
|
||||
|
|
|
|||
|
|
@ -36,18 +36,21 @@ final class PeerInfoHeaderNavigationButtonContainerNode: SparseNode {
|
|||
|
||||
private var backgroundContentColor: UIColor = .clear
|
||||
private var contentsColor: UIColor = .white
|
||||
private var canBeExpanded: Bool = false
|
||||
|
||||
var performAction: ((PeerInfoHeaderNavigationButtonKey, ContextReferenceContentNode?, ContextGesture?) -> Void)?
|
||||
|
||||
func updateContentsColor(backgroundContentColor: UIColor, contentsColor: UIColor, transition: ContainedViewLayoutTransition) {
|
||||
func updateContentsColor(backgroundContentColor: UIColor, contentsColor: UIColor, canBeExpanded: Bool, transition: ContainedViewLayoutTransition) {
|
||||
self.backgroundContentColor = backgroundContentColor
|
||||
self.contentsColor = contentsColor
|
||||
|
||||
for (_, button) in self.leftButtonNodes {
|
||||
button.updateContentsColor(backgroundColor: self.backgroundContentColor, contentsColor: self.contentsColor, transition: transition)
|
||||
button.updateContentsColor(backgroundColor: self.backgroundContentColor, contentsColor: self.contentsColor, canBeExpanded: canBeExpanded, transition: transition)
|
||||
transition.updateSublayerTransformOffset(layer: button.layer, offset: CGPoint(x: canBeExpanded ? -8.0 : 0.0, y: 0.0))
|
||||
}
|
||||
for (_, button) in self.rightButtonNodes {
|
||||
button.updateContentsColor(backgroundColor: self.backgroundContentColor, contentsColor: self.contentsColor, transition: transition)
|
||||
button.updateContentsColor(backgroundColor: self.backgroundContentColor, contentsColor: self.contentsColor, canBeExpanded: canBeExpanded, transition: transition)
|
||||
transition.updateSublayerTransformOffset(layer: button.layer, offset: CGPoint(x: canBeExpanded ? 8.0 : 0.0, y: 0.0))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -106,7 +109,7 @@ final class PeerInfoHeaderNavigationButtonContainerNode: SparseNode {
|
|||
buttonNode.frame = buttonFrame
|
||||
buttonNode.alpha = 0.0
|
||||
transition.updateAlpha(node: buttonNode, alpha: alphaFactor * alphaFactor)
|
||||
buttonNode.updateContentsColor(backgroundColor: self.backgroundContentColor, contentsColor: self.contentsColor, transition: .immediate)
|
||||
buttonNode.updateContentsColor(backgroundColor: self.backgroundContentColor, contentsColor: self.contentsColor, canBeExpanded: self.canBeExpanded, transition: .immediate)
|
||||
} else {
|
||||
transition.updateFrameAdditiveToCenter(node: buttonNode, frame: buttonFrame)
|
||||
transition.updateAlpha(node: buttonNode, alpha: alphaFactor * alphaFactor)
|
||||
|
|
@ -202,7 +205,7 @@ final class PeerInfoHeaderNavigationButtonContainerNode: SparseNode {
|
|||
}
|
||||
let alphaFactor: CGFloat = spec.isForExpandedView ? expandFraction : (1.0 - expandFraction)
|
||||
if wasAdded {
|
||||
buttonNode.updateContentsColor(backgroundColor: self.backgroundContentColor, contentsColor: self.contentsColor, transition: .immediate)
|
||||
buttonNode.updateContentsColor(backgroundColor: self.backgroundContentColor, contentsColor: self.contentsColor, canBeExpanded: self.canBeExpanded, transition: .immediate)
|
||||
|
||||
if key == .moreToSearch {
|
||||
buttonNode.layer.animateScale(from: 0.001, to: 1.0, duration: 0.2)
|
||||
|
|
|
|||
|
|
@ -553,6 +553,7 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
|||
let navigationContentsAccentColor: UIColor
|
||||
let navigationContentsPrimaryColor: UIColor
|
||||
let navigationContentsSecondaryColor: UIColor
|
||||
let navigationContentsCanBeExpanded: Bool
|
||||
|
||||
let contentButtonBackgroundColor: UIColor
|
||||
let contentButtonForegroundColor: UIColor
|
||||
|
|
@ -640,6 +641,8 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
|||
navigationContentsAccentColor = collapsedHeaderNavigationContentsAccentColor
|
||||
navigationContentsPrimaryColor = collapsedHeaderNavigationContentsPrimaryColor
|
||||
navigationContentsSecondaryColor = collapsedHeaderNavigationContentsSecondaryColor
|
||||
navigationContentsCanBeExpanded = true
|
||||
|
||||
contentButtonBackgroundColor = collapsedHeaderContentButtonBackgroundColor
|
||||
contentButtonForegroundColor = collapsedHeaderContentButtonForegroundColor
|
||||
|
||||
|
|
@ -651,6 +654,8 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
|||
contentButtonBackgroundColor = expandedAvatarContentButtonBackgroundColor
|
||||
contentButtonForegroundColor = expandedAvatarContentButtonForegroundColor
|
||||
|
||||
navigationContentsCanBeExpanded = false
|
||||
|
||||
headerButtonBackgroundColor = expandedAvatarHeaderButtonBackgroundColor
|
||||
} else {
|
||||
let effectiveTransitionFraction: CGFloat = innerBackgroundTransitionFraction < 0.5 ? 0.0 : 1.0
|
||||
|
|
@ -659,6 +664,12 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
|||
navigationContentsPrimaryColor = regularNavigationContentsPrimaryColor.mixedWith(collapsedHeaderNavigationContentsPrimaryColor, alpha: effectiveTransitionFraction)
|
||||
navigationContentsSecondaryColor = regularNavigationContentsSecondaryColor.mixedWith(collapsedHeaderNavigationContentsSecondaryColor, alpha: effectiveTransitionFraction)
|
||||
|
||||
if peer?.profileColor != nil {
|
||||
navigationContentsCanBeExpanded = effectiveTransitionFraction == 1.0
|
||||
} else {
|
||||
navigationContentsCanBeExpanded = true
|
||||
}
|
||||
|
||||
contentButtonBackgroundColor = regularContentButtonBackgroundColor//.mixedWith(collapsedHeaderContentButtonBackgroundColor, alpha: effectiveTransitionFraction)
|
||||
contentButtonForegroundColor = regularContentButtonForegroundColor//.mixedWith(collapsedHeaderContentButtonForegroundColor, alpha: effectiveTransitionFraction)
|
||||
|
||||
|
|
@ -775,7 +786,7 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
|||
self.titleExpandedCredibilityIconSize = expandedIconSize
|
||||
}
|
||||
|
||||
self.navigationButtonContainer.updateContentsColor(backgroundContentColor: headerButtonBackgroundColor, contentsColor: navigationContentsAccentColor, transition: navigationTransition)
|
||||
self.navigationButtonContainer.updateContentsColor(backgroundContentColor: headerButtonBackgroundColor, contentsColor: navigationContentsAccentColor, canBeExpanded: navigationContentsCanBeExpanded, transition: navigationTransition)
|
||||
|
||||
self.titleNode.updateTintColor(color: navigationContentsPrimaryColor, transition: navigationTransition)
|
||||
self.subtitleNode.updateTintColor(color: navigationContentsSecondaryColor, transition: navigationTransition)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue