mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-23 14:45:21 +00:00
Update QR auth UI
This commit is contained in:
@@ -6,161 +6,279 @@ import Display
|
||||
import SolidRoundedButtonNode
|
||||
import SwiftSignalKit
|
||||
import OverlayStatusController
|
||||
import AnimatedStickerNode
|
||||
import TelegramPresentationData
|
||||
import TelegramCore
|
||||
import AnimationUI
|
||||
import AccountContext
|
||||
import TelegramPresentationData
|
||||
import PresentationDataUtils
|
||||
import TelegramCore
|
||||
import Markdown
|
||||
|
||||
final class AuthTransferConfirmationNode: ASDisplayNode {
|
||||
public final class AuthDataTransferSplashScreen: ViewController {
|
||||
private let context: AccountContext
|
||||
private let activeSessionsContext: ActiveSessionsContext
|
||||
private var presentationData: PresentationData
|
||||
private let tokenInfo: AuthTransferTokenInfo
|
||||
|
||||
private let containerNode: ASDisplayNode
|
||||
private let backgroundNode: ASImageNode
|
||||
private let iconNode: ASImageNode
|
||||
private let titleNode: ImmediateTextNode
|
||||
private let appNameNode: ImmediateTextNode
|
||||
private let locationInfoNode: ImmediateTextNode
|
||||
private let acceptButtonNode: SolidRoundedButtonNode
|
||||
private let cancelButtonNode: SolidRoundedButtonNode
|
||||
|
||||
private var validLayout: (ContainerViewLayout, CGFloat)?
|
||||
|
||||
init(context: AccountContext, presentationData: PresentationData, tokenInfo: AuthTransferTokenInfo, accept: @escaping () -> Void, cancel: @escaping () -> Void) {
|
||||
public init(context: AccountContext, activeSessionsContext: ActiveSessionsContext) {
|
||||
self.context = context
|
||||
self.activeSessionsContext = activeSessionsContext
|
||||
|
||||
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
|
||||
let defaultTheme = NavigationBarTheme(rootControllerTheme: self.presentationData.theme)
|
||||
let navigationBarTheme = NavigationBarTheme(buttonColor: defaultTheme.buttonColor, disabledButtonColor: defaultTheme.disabledButtonColor, primaryTextColor: defaultTheme.primaryTextColor, backgroundColor: .clear, separatorColor: .clear, badgeBackgroundColor: defaultTheme.badgeBackgroundColor, badgeStrokeColor: defaultTheme.badgeStrokeColor, badgeTextColor: defaultTheme.badgeTextColor)
|
||||
|
||||
super.init(navigationBarPresentationData: NavigationBarPresentationData(theme: navigationBarTheme, strings: NavigationBarStrings(back: self.presentationData.strings.Common_Back, close: self.presentationData.strings.Common_Close)))
|
||||
|
||||
self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBarStyle.style
|
||||
self.navigationPresentation = .modalInLargeLayout
|
||||
self.supportedOrientations = ViewControllerSupportedOrientations(regularSize: .all, compactSize: .portrait)
|
||||
self.navigationBar?.intrinsicCanTransitionInline = false
|
||||
|
||||
self.navigationItem.backBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Back, style: .plain, target: nil, action: nil)
|
||||
}
|
||||
|
||||
required init(coder aDecoder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
deinit {
|
||||
}
|
||||
|
||||
override public func loadDisplayNode() {
|
||||
self.displayNode = AuthDataTransferSplashScreenNode(context: self.context, presentationData: self.presentationData, action: { [weak self] in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
(strongSelf.navigationController as? NavigationController)?.replaceController(strongSelf, with: AuthTransferScanScreen(context: strongSelf.context, activeSessionsContext: strongSelf.activeSessionsContext), animated: true)
|
||||
})
|
||||
|
||||
self.displayNodeDidLoad()
|
||||
}
|
||||
|
||||
override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
|
||||
super.containerLayoutUpdated(layout, transition: transition)
|
||||
|
||||
(self.displayNode as! AuthDataTransferSplashScreenNode).containerLayoutUpdated(layout: layout, navigationHeight: self.navigationHeight, transition: transition)
|
||||
}
|
||||
}
|
||||
|
||||
private final class AuthDataTransferSplashScreenNode: ViewControllerTracingNode {
|
||||
private var presentationData: PresentationData
|
||||
|
||||
private var animationSize: CGSize = CGSize()
|
||||
private var animationOffset: CGPoint = CGPoint()
|
||||
private let animationNode: AnimationNode
|
||||
private let titleNode: ImmediateTextNode
|
||||
private let badgeBackgroundNodes: [ASImageNode]
|
||||
private let badgeTextNodes: [ImmediateTextNode]
|
||||
private let textNodes: [ImmediateTextNode]
|
||||
let buttonNode: SolidRoundedButtonNode
|
||||
|
||||
var inProgress: Bool = false {
|
||||
didSet {
|
||||
self.buttonNode.isUserInteractionEnabled = !self.inProgress
|
||||
self.buttonNode.alpha = self.inProgress ? 0.6 : 1.0
|
||||
}
|
||||
}
|
||||
|
||||
private var validLayout: ContainerViewLayout?
|
||||
|
||||
init(context: AccountContext, presentationData: PresentationData, action: @escaping () -> Void) {
|
||||
self.presentationData = presentationData
|
||||
self.tokenInfo = tokenInfo
|
||||
|
||||
self.containerNode = ASDisplayNode()
|
||||
self.animationNode = AnimationNode(animation: "anim_qr", colors: nil, scale: UIScreenScale)
|
||||
|
||||
self.backgroundNode = ASImageNode()
|
||||
self.backgroundNode.displayWithoutProcessing = true
|
||||
self.backgroundNode.displaysAsynchronously = false
|
||||
self.backgroundNode.image = generateStretchableFilledCircleImage(diameter: 24.0, color: self.presentationData.theme.list.plainBackgroundColor)
|
||||
let buttonText: String
|
||||
|
||||
self.iconNode = ASImageNode()
|
||||
self.iconNode.displayWithoutProcessing = true
|
||||
self.iconNode.displaysAsynchronously = false
|
||||
self.iconNode.image = UIImage(bundleImageName: "Settings/TransferAuthLaptop")
|
||||
let badgeFont = Font.with(size: 14.0, design: .round, traits: [.bold])
|
||||
let textFont = Font.regular(18.0)
|
||||
let textColor = self.presentationData.theme.list.itemPrimaryTextColor
|
||||
|
||||
var badgeBackgroundNodes: [ASImageNode] = []
|
||||
var badgeTextNodes: [ImmediateTextNode] = []
|
||||
var textNodes: [ImmediateTextNode] = []
|
||||
|
||||
let badgeBackground = generateFilledCircleImage(diameter: 20.0, color: self.presentationData.theme.list.itemCheckColors.fillColor)
|
||||
|
||||
for i in 0 ..< 3 {
|
||||
let badgeBackgroundNode = ASImageNode()
|
||||
badgeBackgroundNode.displaysAsynchronously = false
|
||||
badgeBackgroundNode.displayWithoutProcessing = true
|
||||
badgeBackgroundNode.image = badgeBackground
|
||||
badgeBackgroundNodes.append(badgeBackgroundNode)
|
||||
|
||||
let badgeTextNode = ImmediateTextNode()
|
||||
badgeTextNode.displaysAsynchronously = false
|
||||
badgeTextNode.attributedText = NSAttributedString(string: "\(i + 1)", font: badgeFont, textColor: self.presentationData.theme.list.itemCheckColors.foregroundColor)
|
||||
badgeTextNode.maximumNumberOfLines = 0
|
||||
badgeTextNode.lineSpacing = 0.1
|
||||
badgeTextNodes.append(badgeTextNode)
|
||||
|
||||
let string: String
|
||||
switch i {
|
||||
case 0:
|
||||
string = self.presentationData.strings.AuthSessions_AddDeviceIntro_Text1
|
||||
case 1:
|
||||
string = self.presentationData.strings.AuthSessions_AddDeviceIntro_Text2
|
||||
default:
|
||||
string = self.presentationData.strings.AuthSessions_AddDeviceIntro_Text3
|
||||
}
|
||||
|
||||
let body = MarkdownAttributeSet(font: textFont, textColor: textColor)
|
||||
let link = MarkdownAttributeSet(font: textFont, textColor: self.presentationData.theme.list.itemAccentColor, additionalAttributes: ["URL": true as NSNumber])
|
||||
|
||||
let text = parseMarkdownIntoAttributedString(string, attributes: MarkdownAttributes(body: body, bold: body, link: link, linkAttribute: { _ in
|
||||
return nil
|
||||
}))
|
||||
|
||||
let textNode = ImmediateTextNode()
|
||||
textNode.displaysAsynchronously = false
|
||||
textNode.attributedText = text
|
||||
textNode.maximumNumberOfLines = 0
|
||||
textNode.lineSpacing = 0.1
|
||||
textNodes.append(textNode)
|
||||
}
|
||||
|
||||
self.badgeBackgroundNodes = badgeBackgroundNodes
|
||||
self.badgeTextNodes = badgeTextNodes
|
||||
self.textNodes = textNodes
|
||||
|
||||
buttonText = self.presentationData.strings.AuthSessions_AddDeviceIntro_Action
|
||||
|
||||
self.titleNode = ImmediateTextNode()
|
||||
self.titleNode.displaysAsynchronously = false
|
||||
self.titleNode.attributedText = NSAttributedString(string: self.presentationData.strings.AuthSessions_AddDeviceIntro_Title, font: Font.bold(28.0), textColor: self.presentationData.theme.list.itemPrimaryTextColor)
|
||||
self.titleNode.maximumNumberOfLines = 0
|
||||
self.titleNode.textAlignment = .center
|
||||
self.titleNode.maximumNumberOfLines = 2
|
||||
|
||||
self.appNameNode = ImmediateTextNode()
|
||||
self.appNameNode.textAlignment = .center
|
||||
self.appNameNode.maximumNumberOfLines = 2
|
||||
|
||||
self.locationInfoNode = ImmediateTextNode()
|
||||
self.locationInfoNode.textAlignment = .center
|
||||
self.locationInfoNode.maximumNumberOfLines = 0
|
||||
|
||||
self.acceptButtonNode = SolidRoundedButtonNode(title: presentationData.strings.AuthSessions_AddDevice_ConfirmDevice, icon: nil, theme: SolidRoundedButtonTheme(backgroundColor: self.presentationData.theme.list.itemDestructiveColor, foregroundColor: self.presentationData.theme.list.itemCheckColors.foregroundColor), height: 50.0, cornerRadius: 10.0, gloss: false)
|
||||
self.cancelButtonNode = SolidRoundedButtonNode(title: self.presentationData.strings.Common_Cancel, icon: nil, theme: SolidRoundedButtonTheme(backgroundColor: self.presentationData.theme.list.itemCheckColors.fillColor, foregroundColor: self.presentationData.theme.list.itemCheckColors.foregroundColor), height: 50.0, cornerRadius: 10.0, gloss: false)
|
||||
self.buttonNode = SolidRoundedButtonNode(title: buttonText, theme: SolidRoundedButtonTheme(backgroundColor: self.presentationData.theme.list.itemCheckColors.fillColor, foregroundColor: self.presentationData.theme.list.itemCheckColors.foregroundColor), height: 50.0, cornerRadius: 10.0, gloss: false)
|
||||
self.buttonNode.isHidden = buttonText.isEmpty
|
||||
|
||||
super.init()
|
||||
|
||||
self.addSubnode(self.containerNode)
|
||||
self.containerNode.addSubnode(self.backgroundNode)
|
||||
self.containerNode.addSubnode(self.iconNode)
|
||||
self.containerNode.addSubnode(self.titleNode)
|
||||
self.containerNode.addSubnode(self.appNameNode)
|
||||
self.containerNode.addSubnode(self.locationInfoNode)
|
||||
self.containerNode.addSubnode(self.acceptButtonNode)
|
||||
self.containerNode.addSubnode(self.cancelButtonNode)
|
||||
|
||||
let titleFont = Font.bold(24.0)
|
||||
let subtitleFont = Font.regular(16.0)
|
||||
let textColor = self.presentationData.theme.list.itemPrimaryTextColor
|
||||
let seccondaryTextColor = self.presentationData.theme.list.itemSecondaryTextColor
|
||||
self.backgroundColor = self.presentationData.theme.list.plainBackgroundColor
|
||||
|
||||
self.titleNode.attributedText = NSAttributedString(string: "\(tokenInfo.appName)", font: titleFont, textColor: textColor)
|
||||
self.addSubnode(self.animationNode)
|
||||
self.addSubnode(self.titleNode)
|
||||
|
||||
self.appNameNode.attributedText = NSAttributedString(string: "\(tokenInfo.deviceModel), \(tokenInfo.platform) \(tokenInfo.systemVersion)", font: subtitleFont, textColor: seccondaryTextColor)
|
||||
self.badgeBackgroundNodes.forEach(self.addSubnode)
|
||||
self.badgeTextNodes.forEach(self.addSubnode)
|
||||
self.textNodes.forEach(self.addSubnode)
|
||||
|
||||
self.locationInfoNode.attributedText = NSAttributedString(string: "\(tokenInfo.region)\nIP: \(tokenInfo.ip)", font: subtitleFont, textColor: seccondaryTextColor)
|
||||
self.addSubnode(self.buttonNode)
|
||||
|
||||
self.acceptButtonNode.pressed = { [weak self] in
|
||||
accept()
|
||||
self.buttonNode.pressed = {
|
||||
action()
|
||||
}
|
||||
self.cancelButtonNode.pressed = {
|
||||
cancel()
|
||||
|
||||
for textNode in self.textNodes {
|
||||
textNode.linkHighlightColor = self.presentationData.theme.list.itemAccentColor.withAlphaComponent(0.5)
|
||||
textNode.highlightAttributeAction = { attributes in
|
||||
if let _ = attributes[NSAttributedString.Key(rawValue: "URL")] {
|
||||
return NSAttributedString.Key(rawValue: "URL")
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
textNode.tapAttributeAction = { attributes in
|
||||
if let _ = attributes[NSAttributedString.Key(rawValue: "URL")] {
|
||||
context.sharedContext.openExternalUrl(context: context, urlContext: .generic, url: "https://telegram.org/desktop", forceExternal: true, presentationData: context.sharedContext.currentPresentationData.with { $0 }, navigationController: nil, dismissInput: {})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override func didLoad() {
|
||||
super.didLoad()
|
||||
}
|
||||
|
||||
func animateIn() {
|
||||
self.containerNode.layer.animatePosition(from: CGPoint(x: 0.0, y: self.containerNode.bounds.height), to: CGPoint(), duration: 0.5, timingFunction: kCAMediaTimingFunctionSpring, additive: true)
|
||||
}
|
||||
|
||||
func animateOut(completion: @escaping () -> Void) {
|
||||
self.containerNode.layer.animatePosition(from: CGPoint(), to: CGPoint(x: 0.0, y: self.containerNode.bounds.height), duration: 0.3, removeOnCompletion: false, additive: true, completion: { _ in
|
||||
completion()
|
||||
})
|
||||
}
|
||||
|
||||
func updateLayout(layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
|
||||
var insets = layout.insets(options: [])
|
||||
func containerLayoutUpdated(layout: ContainerViewLayout, navigationHeight: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||
let firstTime = self.validLayout == nil
|
||||
self.validLayout = layout
|
||||
|
||||
let sideInset: CGFloat = 22.0
|
||||
|
||||
let buttonSideInset: CGFloat = 16.0
|
||||
let bottomInset = insets.bottom + 10.0
|
||||
let buttonWidth = layout.size.width - buttonSideInset * 2.0
|
||||
let textSideInset: CGFloat = 54.0
|
||||
let buttonSideInset: CGFloat = 48.0
|
||||
let titleSpacing: CGFloat = 30.0
|
||||
let buttonHeight: CGFloat = 50.0
|
||||
let buttonSpacing: CGFloat = 20.0
|
||||
let contentButtonSpacing: CGFloat = 35.0
|
||||
let titleSpacing: CGFloat = 1.0
|
||||
let locationSpacing: CGFloat = 35.0
|
||||
let iconSpacing: CGFloat = 35.0
|
||||
let topInset: CGFloat = 35.0
|
||||
let buttonSpacing: CGFloat = 10.0
|
||||
let textSpacing: CGFloat = 26.0
|
||||
let badgeSize: CGFloat = 20.0
|
||||
|
||||
let iconSize = self.iconNode.image?.size ?? CGSize(width: 10.0, height: 1.0)
|
||||
let titleSize = self.titleNode.updateLayout(CGSize(width: layout.size.width - sideInset * 2.0, height: .greatestFiniteMagnitude))
|
||||
let appNameSize = self.appNameNode.updateLayout(CGSize(width: layout.size.width - sideInset * 2.0, height: .greatestFiniteMagnitude))
|
||||
let locationSize = self.locationInfoNode.updateLayout(CGSize(width: layout.size.width - sideInset * 2.0, height: .greatestFiniteMagnitude))
|
||||
let animationFitSize = CGSize(width: min(500.0, layout.size.width - sideInset), height: 500.0)
|
||||
let animationSize = self.animationNode.preferredSize()?.fitted(animationFitSize) ?? animationFitSize
|
||||
let iconSize: CGSize = animationSize
|
||||
var iconOffset = CGPoint()
|
||||
|
||||
var contentHeight: CGFloat = 0.0
|
||||
contentHeight += topInset + iconSize.height
|
||||
contentHeight += iconSpacing + titleSize.height
|
||||
contentHeight += titleSpacing + appNameSize.height
|
||||
contentHeight += locationSpacing + locationSize.height
|
||||
contentHeight += contentButtonSpacing + bottomInset + buttonHeight + buttonSpacing + buttonHeight
|
||||
let titleSize = self.titleNode.updateLayout(CGSize(width: layout.size.width - sideInset * 2.0, height: layout.size.height))
|
||||
|
||||
let iconFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - iconSize.width) / 2.0), y: topInset), size: iconSize)
|
||||
transition.updateFrame(node: self.iconNode, frame: iconFrame)
|
||||
|
||||
let titleFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - titleSize.width) / 2.0), y: iconFrame.maxY + iconSpacing), size: titleSize)
|
||||
transition.updateFrame(node: self.titleNode, frame: titleFrame)
|
||||
|
||||
let appNameFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - appNameSize.width) / 2.0), y: titleFrame.maxY + titleSpacing), size: appNameSize)
|
||||
transition.updateFrame(node: self.appNameNode, frame: appNameFrame)
|
||||
|
||||
let locationFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - locationSize.width) / 2.0), y: appNameFrame.maxY + locationSpacing), size: locationSize)
|
||||
transition.updateFrame(node: self.locationInfoNode, frame: locationFrame)
|
||||
|
||||
let cancelButtonFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - buttonWidth) / 2.0), y: contentHeight - bottomInset - buttonHeight), size: CGSize(width: buttonWidth, height: buttonHeight))
|
||||
transition.updateFrame(node: self.cancelButtonNode, frame: cancelButtonFrame)
|
||||
self.cancelButtonNode.updateLayout(width: cancelButtonFrame.width, transition: transition)
|
||||
|
||||
let acceptButtonFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - buttonWidth) / 2.0), y: cancelButtonFrame.minY - buttonSpacing - buttonHeight), size: CGSize(width: buttonWidth, height: buttonHeight))
|
||||
transition.updateFrame(node: self.acceptButtonNode, frame: acceptButtonFrame)
|
||||
self.acceptButtonNode.updateLayout(width: acceptButtonFrame.width, transition: transition)
|
||||
|
||||
transition.updateFrame(node: self.containerNode, frame: CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - contentHeight), size: CGSize(width: layout.size.width, height: contentHeight)))
|
||||
transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: layout.size.width, height: contentHeight + 24.0)))
|
||||
}
|
||||
|
||||
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
||||
if let result = self.cancelButtonNode.view.hitTest(self.view.convert(point, to: self.cancelButtonNode.view), with: event) {
|
||||
return result
|
||||
var badgeTextSizes: [CGSize] = []
|
||||
var textSizes: [CGSize] = []
|
||||
var textContentHeight: CGFloat = 0.0
|
||||
for i in 0 ..< self.badgeTextNodes.count {
|
||||
let badgeTextSize = self.badgeTextNodes[i].updateLayout(CGSize(width: 100.0, height: .greatestFiniteMagnitude))
|
||||
badgeTextSizes.append(badgeTextSize)
|
||||
let textSize = self.textNodes[i].updateLayout(CGSize(width: layout.size.width - sideInset * 2.0 - 40.0, height: .greatestFiniteMagnitude))
|
||||
textSizes.append(textSize)
|
||||
|
||||
if i != 0 {
|
||||
textContentHeight += textSpacing
|
||||
}
|
||||
textContentHeight += textSize.height
|
||||
}
|
||||
if let result = self.acceptButtonNode.view.hitTest(self.view.convert(point, to: self.acceptButtonNode.view), with: event) {
|
||||
return result
|
||||
|
||||
var contentHeight = iconSize.height + titleSize.height + titleSpacing + textContentHeight
|
||||
|
||||
let bottomInset = layout.intrinsicInsets.bottom + 20.0
|
||||
let contentTopInset = navigationHeight
|
||||
let contentBottomInset = bottomInset + buttonHeight + buttonSpacing
|
||||
|
||||
let iconSpacing: CGFloat = max(20.0, min(64.0, layout.size.height - contentTopInset - contentBottomInset - contentHeight - 40.0))
|
||||
|
||||
contentHeight += iconSpacing
|
||||
|
||||
var contentVerticalOrigin = contentTopInset + floor((layout.size.height - contentTopInset - contentBottomInset - contentHeight) / 2.0)
|
||||
|
||||
let buttonWidth = layout.size.width - buttonSideInset * 2.0
|
||||
|
||||
let buttonFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - buttonWidth) / 2.0), y: layout.size.height - bottomInset - buttonHeight), size: CGSize(width: buttonWidth, height: buttonHeight))
|
||||
transition.updateFrame(node: self.buttonNode, frame: buttonFrame)
|
||||
self.buttonNode.updateLayout(width: buttonFrame.width, transition: transition)
|
||||
|
||||
var maxContentVerticalOrigin = buttonFrame.minY - 12.0 - contentHeight
|
||||
|
||||
contentVerticalOrigin = min(contentVerticalOrigin, maxContentVerticalOrigin)
|
||||
|
||||
var contentY = contentVerticalOrigin
|
||||
let iconFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - iconSize.width) / 2.0) + self.animationOffset.x, y: contentY), size: iconSize).offsetBy(dx: iconOffset.x, dy: iconOffset.y)
|
||||
contentY += iconSize.height + iconSpacing
|
||||
transition.updateFrameAdditive(node: self.animationNode, frame: iconFrame)
|
||||
|
||||
let titleFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - titleSize.width) / 2.0), y: contentY), size: titleSize)
|
||||
transition.updateFrameAdditive(node: self.titleNode, frame: titleFrame)
|
||||
contentY += titleSize.height + titleSpacing
|
||||
|
||||
for i in 0 ..< self.badgeTextNodes.count {
|
||||
if i != 0 {
|
||||
contentY += textSpacing
|
||||
}
|
||||
|
||||
let badgeTextSize = badgeTextSizes[i]
|
||||
let textSize = textSizes[i]
|
||||
|
||||
let textFrame = CGRect(origin: CGPoint(x: textSideInset, y: contentY), size: textSize)
|
||||
transition.updateFrameAdditive(node: self.textNodes[i], frame: textFrame)
|
||||
|
||||
let badgeFrame = CGRect(origin: CGPoint(x: sideInset, y: textFrame.minY + floor((textFrame.height - badgeSize) / 2.0)), size: CGSize(width: badgeSize, height: badgeSize))
|
||||
transition.updateFrameAdditive(node: self.badgeBackgroundNodes[i], frame: badgeFrame)
|
||||
|
||||
transition.updateFrameAdditive(node: self.badgeTextNodes[i], frame: CGRect(origin: CGPoint(x: badgeFrame.minX + floor((badgeFrame.width - badgeTextSize.width) / 2.0) + 0.5, y: badgeFrame.minY + floor((badgeFrame.height - badgeTextSize.height) / 2.0) + 0.5), size: badgeTextSize))
|
||||
|
||||
contentY += textSize.height
|
||||
}
|
||||
|
||||
if firstTime {
|
||||
self.animationNode.play()
|
||||
}
|
||||
return super.hitTest(point, with: event)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user