mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-23 06:35:51 +00:00
Wallet QR code scanner and other improvements
This commit is contained in:
178
submodules/GlassButtonNode/Sources/GlassButtonNode.swift
Normal file
178
submodules/GlassButtonNode/Sources/GlassButtonNode.swift
Normal file
@@ -0,0 +1,178 @@
|
||||
import Foundation
|
||||
import Display
|
||||
import AsyncDisplayKit
|
||||
import SwiftSignalKit
|
||||
|
||||
private let largeButtonSize = CGSize(width: 72.0, height: 72.0)
|
||||
private let smallButtonSize = CGSize(width: 60.0, height: 60.0)
|
||||
|
||||
private func generateEmptyButtonImage(icon: UIImage?, strokeColor: UIColor?, fillColor: UIColor, knockout: Bool = false, angle: CGFloat = 0.0, buttonSize: CGSize = smallButtonSize) -> UIImage? {
|
||||
return generateImage(buttonSize, contextGenerator: { size, context in
|
||||
context.clear(CGRect(origin: CGPoint(), size: size))
|
||||
context.setBlendMode(.copy)
|
||||
if let strokeColor = strokeColor {
|
||||
context.setFillColor(strokeColor.cgColor)
|
||||
context.fillEllipse(in: CGRect(origin: CGPoint(), size: size))
|
||||
context.setFillColor(fillColor.cgColor)
|
||||
context.fillEllipse(in: CGRect(origin: CGPoint(x: 1.5, y: 1.5), size: CGSize(width: size.width - 3.0, height: size.height - 3.0)))
|
||||
} else {
|
||||
context.setFillColor(fillColor.cgColor)
|
||||
context.fillEllipse(in: CGRect(origin: CGPoint(), size: CGSize(width: size.width, height: size.height)))
|
||||
}
|
||||
|
||||
if let icon = icon {
|
||||
if !angle.isZero {
|
||||
context.translateBy(x: size.width / 2.0, y: size.height / 2.0)
|
||||
context.rotate(by: angle)
|
||||
context.translateBy(x: -size.width / 2.0, y: -size.height / 2.0)
|
||||
}
|
||||
let imageSize = icon.size
|
||||
let imageRect = CGRect(origin: CGPoint(x: floor((size.width - imageSize.width) / 2.0), y: floor((size.width - imageSize.height) / 2.0)), size: imageSize)
|
||||
if knockout {
|
||||
context.setBlendMode(.copy)
|
||||
context.clip(to: imageRect, mask: icon.cgImage!)
|
||||
context.setFillColor(UIColor.clear.cgColor)
|
||||
context.fill(imageRect)
|
||||
} else {
|
||||
context.setBlendMode(.normal)
|
||||
context.draw(icon.cgImage!, in: imageRect)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private func generateFilledButtonImage(color: UIColor, icon: UIImage?, angle: CGFloat = 0.0, buttonSize: CGSize = smallButtonSize) -> UIImage? {
|
||||
return generateImage(buttonSize, contextGenerator: { size, context in
|
||||
context.clear(CGRect(origin: CGPoint(), size: size))
|
||||
context.setBlendMode(.normal)
|
||||
context.setFillColor(color.cgColor)
|
||||
context.fillEllipse(in: CGRect(origin: CGPoint(), size: size))
|
||||
|
||||
if let icon = icon {
|
||||
if !angle.isZero {
|
||||
context.translateBy(x: size.width / 2.0, y: size.height / 2.0)
|
||||
context.rotate(by: angle)
|
||||
context.translateBy(x: -size.width / 2.0, y: -size.height / 2.0)
|
||||
}
|
||||
context.draw(icon.cgImage!, in: CGRect(origin: CGPoint(x: floor((size.width - icon.size.width) / 2.0), y: floor((size.height - icon.size.height) / 2.0)), size: icon.size))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private let emptyHighlightedFill = UIColor(white: 1.0, alpha: 0.3)
|
||||
private let invertedFill = UIColor(white: 1.0, alpha: 1.0)
|
||||
|
||||
private let largeLabelFont = Font.regular(14.5)
|
||||
private let smallLabelFont = Font.regular(11.5)
|
||||
|
||||
public final class GlassButtonNode: HighlightTrackingButtonNode {
|
||||
private var regularImage: UIImage?
|
||||
private var highlightedImage: UIImage?
|
||||
private var filledImage: UIImage?
|
||||
|
||||
private let blurView: UIVisualEffectView
|
||||
private let iconNode: ASImageNode
|
||||
private var labelNode: ASTextNode?
|
||||
|
||||
public init(icon: UIImage, label: String?) {
|
||||
let blurView = UIVisualEffectView(effect: UIBlurEffect(style: .light))
|
||||
blurView.clipsToBounds = true
|
||||
blurView.isUserInteractionEnabled = false
|
||||
self.blurView = blurView
|
||||
|
||||
self.iconNode = ASImageNode()
|
||||
self.iconNode.isLayerBacked = true
|
||||
self.iconNode.displayWithoutProcessing = false
|
||||
self.iconNode.displaysAsynchronously = false
|
||||
|
||||
self.regularImage = generateEmptyButtonImage(icon: icon, strokeColor: nil, fillColor: .clear, buttonSize: largeButtonSize)
|
||||
self.highlightedImage = generateEmptyButtonImage(icon: icon, strokeColor: nil, fillColor: emptyHighlightedFill, buttonSize: largeButtonSize)
|
||||
self.filledImage = generateEmptyButtonImage(icon: icon, strokeColor: nil, fillColor: invertedFill, knockout: true, buttonSize: largeButtonSize)
|
||||
|
||||
if let label = label {
|
||||
let labelNode = ASTextNode()
|
||||
let labelFont: UIFont
|
||||
if let image = regularImage, image.size.width < 70.0 {
|
||||
labelFont = smallLabelFont
|
||||
} else {
|
||||
labelFont = largeLabelFont
|
||||
}
|
||||
labelNode.attributedText = NSAttributedString(string: label, font: labelFont, textColor: .white)
|
||||
self.labelNode = labelNode
|
||||
} else {
|
||||
self.labelNode = nil
|
||||
}
|
||||
|
||||
super.init()
|
||||
|
||||
self.view.addSubview(blurView)
|
||||
self.addSubnode(self.iconNode)
|
||||
if let labelNode = self.labelNode {
|
||||
self.addSubnode(labelNode)
|
||||
}
|
||||
self.iconNode.image = regularImage
|
||||
self.currentImage = regularImage
|
||||
|
||||
self.highligthedChanged = { [weak self] highlighted in
|
||||
if let strongSelf = self {
|
||||
strongSelf.internalHighlighted = highlighted
|
||||
strongSelf.updateState(highlighted: highlighted, selected: strongSelf.isSelected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var internalHighlighted = false
|
||||
|
||||
override public var isSelected: Bool {
|
||||
didSet {
|
||||
self.updateState(highlighted: self.internalHighlighted, selected: self.isSelected)
|
||||
}
|
||||
}
|
||||
|
||||
private var currentImage: UIImage?
|
||||
|
||||
private func updateState(highlighted: Bool, selected: Bool) {
|
||||
let image: UIImage?
|
||||
if selected {
|
||||
image = self.filledImage
|
||||
} else if highlighted {
|
||||
image = self.highlightedImage
|
||||
} else {
|
||||
image = self.regularImage
|
||||
}
|
||||
|
||||
if self.currentImage !== image {
|
||||
let currentContents = self.iconNode.layer.contents
|
||||
self.iconNode.layer.removeAnimation(forKey: "contents")
|
||||
if let currentContents = currentContents, let image = image {
|
||||
self.iconNode.image = image
|
||||
self.iconNode.layer.animate(from: currentContents as AnyObject, to: image.cgImage!, keyPath: "contents", timingFunction: CAMediaTimingFunctionName.easeInEaseOut.rawValue, duration: image === self.currentImage || image === self.filledImage ? 0.25 : 0.15)
|
||||
} else {
|
||||
self.iconNode.image = image
|
||||
}
|
||||
self.currentImage = image
|
||||
}
|
||||
}
|
||||
|
||||
override public func layout() {
|
||||
super.layout()
|
||||
|
||||
let size = self.bounds.size
|
||||
|
||||
self.blurView.layer.cornerRadius = size.width / 2.0
|
||||
blurView.frame = self.bounds
|
||||
|
||||
self.iconNode.frame = self.bounds
|
||||
|
||||
if let labelNode = self.labelNode {
|
||||
let labelSize = labelNode.measure(CGSize(width: 200.0, height: 100.0))
|
||||
let offset: CGFloat
|
||||
if size.width < 70.0 {
|
||||
offset = 65.0
|
||||
} else {
|
||||
offset = 81.0
|
||||
}
|
||||
labelNode.frame = CGRect(origin: CGPoint(x: floor((size.width - labelSize.width) / 2.0), y: offset), size: labelSize)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user