Swiftgram/submodules/BotPaymentsUI/Sources/BotCheckoutActionButton.swift
2021-08-04 01:30:57 +02:00

146 lines
6.4 KiB
Swift

import Foundation
import UIKit
import AsyncDisplayKit
import Display
import PassKit
import ShimmerEffect
enum BotCheckoutActionButtonState: Equatable {
case active(String)
case applePay
case placeholder
}
private let titleFont = Font.semibold(17.0)
final class BotCheckoutActionButton: HighlightableButtonNode {
static var height: CGFloat = 52.0
private var activeFillColor: UIColor
private var foregroundColor: UIColor
private let activeBackgroundNode: ASImageNode
private var applePayButton: UIButton?
private let labelNode: TextNode
private var state: BotCheckoutActionButtonState?
private var validLayout: (CGRect, CGSize)?
private var placeholderNode: ShimmerEffectNode?
init(activeFillColor: UIColor, foregroundColor: UIColor) {
self.activeFillColor = activeFillColor
self.foregroundColor = foregroundColor
let diameter: CGFloat = 20.0
self.activeBackgroundNode = ASImageNode()
self.activeBackgroundNode.displaysAsynchronously = false
self.activeBackgroundNode.displayWithoutProcessing = true
self.activeBackgroundNode.isLayerBacked = true
self.activeBackgroundNode.image = generateStretchableFilledCircleImage(diameter: diameter, color: activeFillColor)
self.labelNode = TextNode()
self.labelNode.displaysAsynchronously = false
self.labelNode.isUserInteractionEnabled = false
super.init()
self.addSubnode(self.activeBackgroundNode)
self.addSubnode(self.labelNode)
}
func setState(_ state: BotCheckoutActionButtonState) {
if self.state != state {
let previousState = self.state
self.state = state
if let (absoluteRect, containerSize) = self.validLayout, let _ = previousState {
self.updateLayout(absoluteRect: absoluteRect, containerSize: containerSize, transition: .immediate)
}
}
}
@objc private func applePayButtonPressed() {
self.sendActions(forControlEvents: .touchUpInside, with: nil)
}
func updateLayout(absoluteRect: CGRect, containerSize: CGSize, transition: ContainedViewLayoutTransition) {
let size = absoluteRect.size
self.validLayout = (absoluteRect, containerSize)
transition.updateFrame(node: self.activeBackgroundNode, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: size.width, height: BotCheckoutActionButton.height)))
var labelSize = self.labelNode.bounds.size
if let state = self.state {
switch state {
case let .active(title):
if let applePayButton = self.applePayButton {
self.applePayButton = nil
applePayButton.removeFromSuperview()
}
if let placeholderNode = self.placeholderNode {
self.placeholderNode = nil
placeholderNode.removeFromSupernode()
}
let makeLayout = TextNode.asyncLayout(self.labelNode)
let (labelLayout, labelApply) = makeLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: title, font: titleFont, textColor: self.foregroundColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: size, alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
let _ = labelApply()
labelSize = labelLayout.size
case .applePay:
if self.applePayButton == nil {
if #available(iOSApplicationExtension 9.0, iOS 9.0, *) {
let applePayButton: PKPaymentButton
if #available(iOS 14.0, *) {
applePayButton = PKPaymentButton(paymentButtonType: .buy, paymentButtonStyle: .black)
} else {
applePayButton = PKPaymentButton(paymentButtonType: .buy, paymentButtonStyle: .black)
}
applePayButton.addTarget(self, action: #selector(self.applePayButtonPressed), for: .touchUpInside)
self.view.addSubview(applePayButton)
self.applePayButton = applePayButton
}
}
if let placeholderNode = self.placeholderNode {
self.placeholderNode = nil
placeholderNode.removeFromSupernode()
}
if let applePayButton = self.applePayButton {
applePayButton.frame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: size.width, height: BotCheckoutActionButton.height))
}
case .placeholder:
if let applePayButton = self.applePayButton {
self.applePayButton = nil
applePayButton.removeFromSuperview()
}
let contentSize = CGSize(width: 80.0, height: 8.0)
let shimmerNode: ShimmerEffectNode
if let current = self.placeholderNode {
shimmerNode = current
} else {
shimmerNode = ShimmerEffectNode()
self.placeholderNode = shimmerNode
self.addSubnode(shimmerNode)
}
shimmerNode.frame = CGRect(origin: CGPoint(x: floor((size.width - contentSize.width) / 2.0), y: floor((size.height - contentSize.height) / 2.0)), size: contentSize)
shimmerNode.updateAbsoluteRect(CGRect(origin: CGPoint(x: absoluteRect.minX + shimmerNode.frame.minX, y: absoluteRect.minY + shimmerNode.frame.minY), size: contentSize), within: containerSize)
var shapes: [ShimmerEffectNode.Shape] = []
shapes.append(.roundedRectLine(startPoint: CGPoint(x: 0.0, y: 0.0), width: contentSize.width, diameter: contentSize.height))
shimmerNode.update(backgroundColor: self.activeFillColor, foregroundColor: self.activeFillColor.mixedWith(UIColor.white, alpha: 0.25), shimmeringColor: self.activeFillColor.mixedWith(UIColor.white, alpha: 0.15), shapes: shapes, size: contentSize)
}
}
transition.updateFrame(node: self.labelNode, frame: CGRect(origin: CGPoint(x: floor((size.width - labelSize.width) / 2.0), y: floor((size.height - labelSize.height) / 2.0)), size: labelSize))
}
}