mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-10-09 03:20:48 +00:00
Improve QR auth UI
This commit is contained in:
parent
12c99de957
commit
3671fc3761
@ -5143,11 +5143,15 @@ Any member of this group will be able to see messages in the channel.";
|
||||
"Settings.Devices" = "Devices";
|
||||
"Settings.AddDevice" = "Scan QR";
|
||||
"AuthSessions.DevicesTitle" = "Devices";
|
||||
"AuthSessions.AddDevice" = "Scan QR";
|
||||
"AuthSessions.AddDevice" = "Add Device";
|
||||
"AuthSessions.AddDevice.ScanInfo" = "Scan a QR code to log into\nthis account on another device.";
|
||||
"AuthSessions.AddDevice.ScanTitle" = "Scan QR Code";
|
||||
"AuthSessions.AddDevice.ScanApps" = "Telegram is available for\niPhone, iPad, macOS, Windows and Linux";
|
||||
"AuthSessions.AddDevice.ConfirmDevice" = "Confirm Log In";
|
||||
"AuthSessions.AddDevice.InvalidQRCode" = "Invalid QR Code";
|
||||
"AuthSessions.AddDeviceIntro.Title" = "Log in by QR Code";
|
||||
"AuthSessions.AddDeviceIntro.Text1" = "[Download Telegram]() on your computer";
|
||||
"AuthSessions.AddDeviceIntro.Text2" = "Run Telegram on your computer to get the QR code";
|
||||
"AuthSessions.AddDeviceIntro.Text3" = "Scan the QR code to connect your account";
|
||||
"AuthSessions.AddDeviceIntro.Action" = "Scan QR Code";
|
||||
|
||||
"Map.SendThisPlace" = "Send This Place";
|
||||
"Map.SetThisPlace" = "Set This Place";
|
||||
@ -5161,3 +5165,5 @@ Any member of this group will be able to see messages in the channel.";
|
||||
|
||||
"ChatList.Search.ShowMore" = "Show more";
|
||||
"ChatList.Search.ShowLess" = "Show less";
|
||||
|
||||
"AuthSessions.OtherDevices" = "The official Telegram App is available for iPhone, iPad, Android, macOS, Windows and Linux. [Learn More]()";
|
||||
|
@ -21,6 +21,7 @@ static_library(
|
||||
"//submodules/SolidRoundedButtonNode:SolidRoundedButtonNode",
|
||||
"//submodules/OverlayStatusController:OverlayStatusController",
|
||||
"//submodules/AnimatedStickerNode:AnimatedStickerNode",
|
||||
"//submodules/Markdown:Markdown",
|
||||
],
|
||||
frameworks = [
|
||||
"$SDKROOT/System/Library/Frameworks/Foundation.framework",
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -79,6 +79,10 @@ public final class AuthTransferScanScreen: ViewController {
|
||||
private var inForegroundDisposable: Disposable?
|
||||
private let approveDisposable = MetaDisposable()
|
||||
|
||||
private var controllerNode: AuthTransferScanScreenNode {
|
||||
return self.displayNode as! AuthTransferScanScreenNode
|
||||
}
|
||||
|
||||
public init(context: AccountContext, activeSessionsContext: ActiveSessionsContext?) {
|
||||
self.context = context
|
||||
self.activeSessionsContext = activeSessionsContext
|
||||
@ -134,7 +138,10 @@ public final class AuthTransferScanScreen: ViewController {
|
||||
return .single(code)
|
||||
|> delay(0.5, queue: Queue.mainQueue())
|
||||
}).start(next: { [weak self] code in
|
||||
guard let strongSelf = self, let code = code else {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
guard let code = code else {
|
||||
return
|
||||
}
|
||||
if let url = URL(string: code), let parsedToken = parseAuthTransferUrl(url) {
|
||||
@ -143,32 +150,30 @@ public final class AuthTransferScanScreen: ViewController {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
(strongSelf.displayNode as! AuthTransferScanScreenNode).updateTokenPreview(confirmationNode: AuthTransferConfirmationNode(context: strongSelf.context, presentationData: strongSelf.presentationData, tokenInfo: tokenInfo, accept: {
|
||||
strongSelf.approveDisposable.set((approveAuthTransferToken(account: strongSelf.context.account, token: parsedToken)
|
||||
|> deliverOnMainQueue).start(error: { _ in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.approveDisposable.set((approveAuthTransferToken(account: strongSelf.context.account, token: parsedToken)
|
||||
|> deliverOnMainQueue).start(error: { _ in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
(strongSelf.displayNode as! AuthTransferScanScreenNode).updateTokenPreview(confirmationNode: nil)
|
||||
}, completed: {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
let activeSessionsContext = strongSelf.activeSessionsContext
|
||||
Queue.mainQueue().after(1.5, {
|
||||
activeSessionsContext?.loadMore()
|
||||
})
|
||||
strongSelf.dismiss()
|
||||
}))
|
||||
}, cancel: {
|
||||
strongSelf.controllerNode.codeWithError = code
|
||||
strongSelf.controllerNode.updateFocusedRect(nil)
|
||||
}, completed: {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
(strongSelf.displayNode as! AuthTransferScanScreenNode).updateTokenPreview(confirmationNode: nil)
|
||||
strongSelf.controllerNode.codeWithError = nil
|
||||
let activeSessionsContext = strongSelf.activeSessionsContext
|
||||
Queue.mainQueue().after(1.5, {
|
||||
activeSessionsContext?.loadMore()
|
||||
})
|
||||
strongSelf.dismiss()
|
||||
}))
|
||||
}, error: { _ in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.controllerNode.codeWithError = code
|
||||
strongSelf.controllerNode.updateFocusedRect(nil)
|
||||
})
|
||||
}
|
||||
})
|
||||
@ -195,7 +200,7 @@ private final class AuthTransferScanScreenNode: ViewControllerTracingNode, UIScr
|
||||
private let torchButtonNode: GlassButtonNode
|
||||
private let titleNode: ImmediateTextNode
|
||||
private let textNode: ImmediateTextNode
|
||||
private let descriptionNode: ImmediateTextNode
|
||||
private let errorTextNode: ImmediateTextNode
|
||||
|
||||
private let camera: Camera
|
||||
private let codeDisposable = MetaDisposable()
|
||||
@ -203,10 +208,20 @@ private final class AuthTransferScanScreenNode: ViewControllerTracingNode, UIScr
|
||||
fileprivate let focusedCode = ValuePromise<CameraCode?>(ignoreRepeated: true)
|
||||
private var focusedRect: CGRect?
|
||||
|
||||
private(set) var confirmationNode: AuthTransferConfirmationNode?
|
||||
|
||||
private var validLayout: (ContainerViewLayout, CGFloat)?
|
||||
|
||||
var codeWithError: String? {
|
||||
didSet {
|
||||
if self.codeWithError != oldValue {
|
||||
if self.codeWithError != nil {
|
||||
self.errorTextNode.isHidden = false
|
||||
} else {
|
||||
self.errorTextNode.isHidden = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
init(presentationData: PresentationData) {
|
||||
self.presentationData = presentationData
|
||||
|
||||
@ -254,11 +269,12 @@ private final class AuthTransferScanScreenNode: ViewControllerTracingNode, UIScr
|
||||
self.textNode.maximumNumberOfLines = 0
|
||||
self.textNode.textAlignment = .center
|
||||
|
||||
self.descriptionNode = ImmediateTextNode()
|
||||
self.descriptionNode.displaysAsynchronously = false
|
||||
self.descriptionNode.attributedText = NSAttributedString(string: presentationData.strings.AuthSessions_AddDevice_ScanApps, font: Font.regular(14.0), textColor: .white)
|
||||
self.descriptionNode.maximumNumberOfLines = 0
|
||||
self.descriptionNode.textAlignment = .center
|
||||
self.errorTextNode = ImmediateTextNode()
|
||||
self.errorTextNode.displaysAsynchronously = false
|
||||
self.errorTextNode.attributedText = NSAttributedString(string: presentationData.strings.AuthSessions_AddDevice_InvalidQRCode, font: Font.medium(16.0), textColor: .white)
|
||||
self.errorTextNode.maximumNumberOfLines = 0
|
||||
self.errorTextNode.textAlignment = .center
|
||||
//self.errorTextNode.isHidden = true
|
||||
|
||||
self.camera = Camera(configuration: .init(preset: .hd1920x1080, position: .back, audio: false))
|
||||
|
||||
@ -274,10 +290,10 @@ private final class AuthTransferScanScreenNode: ViewControllerTracingNode, UIScr
|
||||
self.addSubnode(self.rightDimNode)
|
||||
self.addSubnode(self.centerDimNode)
|
||||
self.addSubnode(self.frameNode)
|
||||
//self.addSubnode(self.torchButtonNode)
|
||||
self.addSubnode(self.torchButtonNode)
|
||||
self.addSubnode(self.titleNode)
|
||||
self.addSubnode(self.textNode)
|
||||
self.addSubnode(self.descriptionNode)
|
||||
self.addSubnode(self.errorTextNode)
|
||||
|
||||
self.torchButtonNode.addTarget(self, action: #selector(self.torchPressed), forControlEvents: .touchUpInside)
|
||||
}
|
||||
@ -313,44 +329,31 @@ private final class AuthTransferScanScreenNode: ViewControllerTracingNode, UIScr
|
||||
}
|
||||
let filteredCodes = codes.filter { $0.message.hasPrefix("tg://") }
|
||||
if let code = filteredCodes.first, CGRect(x: 0.3, y: 0.3, width: 0.4, height: 0.4).contains(code.boundingBox.center) {
|
||||
strongSelf.focusedCode.set(code)
|
||||
strongSelf.updateFocusedRect(code.boundingBox)
|
||||
if strongSelf.codeWithError != code.message {
|
||||
strongSelf.codeWithError = nil
|
||||
}
|
||||
if strongSelf.codeWithError == code.message {
|
||||
strongSelf.focusedCode.set(nil)
|
||||
strongSelf.updateFocusedRect(nil)
|
||||
} else {
|
||||
strongSelf.focusedCode.set(code)
|
||||
strongSelf.updateFocusedRect(code.boundingBox)
|
||||
}
|
||||
} else {
|
||||
strongSelf.codeWithError = nil
|
||||
strongSelf.focusedCode.set(nil)
|
||||
strongSelf.updateFocusedRect(nil)
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
private func updateFocusedRect(_ rect: CGRect?) {
|
||||
func updateFocusedRect(_ rect: CGRect?) {
|
||||
self.focusedRect = rect
|
||||
if let (layout, navigationHeight) = self.validLayout {
|
||||
self.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: .animated(duration: 0.4, curve: .spring))
|
||||
}
|
||||
}
|
||||
|
||||
func updateTokenPreview(confirmationNode: AuthTransferConfirmationNode?) {
|
||||
if let confirmationNode = self.confirmationNode {
|
||||
confirmationNode.animateOut { [weak confirmationNode] in
|
||||
confirmationNode?.removeFromSupernode()
|
||||
}
|
||||
self.confirmationNode = nil
|
||||
}
|
||||
self.confirmationNode = confirmationNode
|
||||
if let confirmationNode = self.confirmationNode {
|
||||
self.addSubnode(confirmationNode)
|
||||
if let (layout, navigationHeight) = self.validLayout {
|
||||
confirmationNode.updateLayout(layout: layout, transition: .immediate)
|
||||
confirmationNode.animateIn()
|
||||
self.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: .animated(duration: 0.3, curve: .easeInOut))
|
||||
}
|
||||
} else {
|
||||
if let (layout, navigationHeight) = self.validLayout {
|
||||
self.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: .animated(duration: 0.3, curve: .easeInOut))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func containerLayoutUpdated(layout: ContainerViewLayout, navigationHeight: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||
self.validLayout = (layout, navigationHeight)
|
||||
|
||||
@ -379,19 +382,7 @@ private final class AuthTransferScanScreenNode: ViewControllerTracingNode, UIScr
|
||||
let controlsAlpha: CGFloat
|
||||
var centerDimAlpha: CGFloat = 0.0
|
||||
var frameAlpha: CGFloat = 1.0
|
||||
if self.confirmationNode != nil {
|
||||
controlsAlpha = 0.0
|
||||
dimAlpha = 0.625
|
||||
centerDimAlpha = 0.625
|
||||
frameAlpha = 0.0
|
||||
if let focusedRect = self.focusedRect {
|
||||
let side = max(bounds.width * focusedRect.width, bounds.height * focusedRect.height) * 0.6
|
||||
let center = CGPoint(x: (1.0 - focusedRect.center.y) * bounds.width, y: focusedRect.center.x * bounds.height)
|
||||
dimRect = CGRect(x: center.x - side / 2.0, y: center.y - side / 2.0, width: side, height: side)
|
||||
} else {
|
||||
dimRect = CGRect(x: dimInset, y: dimHeight, width: layout.size.width - dimInset * 2.0, height: layout.size.height - dimHeight * 2.0)
|
||||
}
|
||||
} else if let focusedRect = self.focusedRect {
|
||||
if let focusedRect = self.focusedRect {
|
||||
controlsAlpha = 0.0
|
||||
dimAlpha = 1.0
|
||||
let side = max(bounds.width * focusedRect.width, bounds.height * focusedRect.height) * 0.6
|
||||
@ -418,26 +409,22 @@ private final class AuthTransferScanScreenNode: ViewControllerTracingNode, UIScr
|
||||
transition.updateFrame(node: self.centerDimNode, frame: dimRect)
|
||||
|
||||
let buttonSize = CGSize(width: 72.0, height: 72.0)
|
||||
transition.updateFrame(node: self.torchButtonNode, frame: CGRect(origin: CGPoint(x: floor((layout.size.width - buttonSize.width) / 2.0), y: dimHeight + frameSide + 50.0), size: buttonSize))
|
||||
transition.updateFrame(node: self.torchButtonNode, frame: CGRect(origin: CGPoint(x: floor((layout.size.width - buttonSize.width) / 2.0), y: dimHeight + frameSide + 98.0), size: buttonSize))
|
||||
|
||||
transition.updateAlpha(node: self.titleNode, alpha: controlsAlpha)
|
||||
transition.updateAlpha(node: self.textNode, alpha: controlsAlpha)
|
||||
transition.updateAlpha(node: self.descriptionNode, alpha: controlsAlpha)
|
||||
transition.updateAlpha(node: self.errorTextNode, alpha: controlsAlpha)
|
||||
transition.updateAlpha(node: self.torchButtonNode, alpha: controlsAlpha)
|
||||
|
||||
let titleSize = self.titleNode.updateLayout(CGSize(width: layout.size.width - sideInset * 2.0, height: layout.size.height))
|
||||
let textSize = self.textNode.updateLayout(CGSize(width: layout.size.width - sideInset * 2.0, height: layout.size.height))
|
||||
let descriptionSize = self.descriptionNode.updateLayout(CGSize(width: layout.size.width - sideInset * 2.0, height: layout.size.height))
|
||||
let errorTextSize = self.errorTextNode.updateLayout(CGSize(width: layout.size.width - sideInset * 2.0, height: layout.size.height))
|
||||
let textFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - textSize.width) / 2.0), y: dimHeight - textSize.height - titleSpacing), size: textSize)
|
||||
let titleFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - titleSize.width) / 2.0), y: textFrame.minY - 18.0 - titleSize.height), size: titleSize)
|
||||
let descriptionFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - descriptionSize.width) / 2.0), y: layout.size.height - dimHeight + titleSpacing), size: descriptionSize)
|
||||
let errorTextFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - errorTextSize.width) / 2.0), y: dimHeight + frameSide + 48.0), size: errorTextSize)
|
||||
transition.updateFrameAdditive(node: self.titleNode, frame: titleFrame)
|
||||
transition.updateFrameAdditive(node: self.textNode, frame: textFrame)
|
||||
transition.updateFrameAdditive(node: self.descriptionNode, frame: descriptionFrame)
|
||||
|
||||
if let confirmationNode = self.confirmationNode {
|
||||
confirmationNode.updateLayout(layout: layout, transition: transition)
|
||||
}
|
||||
transition.updateFrameAdditive(node: self.errorTextNode, frame: errorTextFrame)
|
||||
}
|
||||
|
||||
@objc private func torchPressed() {
|
||||
|
@ -293,7 +293,7 @@ private enum PrivacyAndSecurityEntry: ItemListNodeEntry {
|
||||
arguments.openTwoStepVerification(data)
|
||||
})
|
||||
case let .activeSessions(theme, text, value):
|
||||
return ItemListDisclosureItem(presentationData: presentationData, icon: UIImage(bundleImageName: "Settings/MenuIcons/Sessions")?.precomposed(), title: text, label: value, sectionId: self.section, style: .blocks, action: {
|
||||
return ItemListDisclosureItem(presentationData: presentationData, icon: UIImage(bundleImageName: "Settings/MenuIcons/Websites")?.precomposed(), title: text, label: value, sectionId: self.section, style: .blocks, action: {
|
||||
arguments.openActiveSessions()
|
||||
})
|
||||
case let .accountHeader(theme, text):
|
||||
|
@ -24,7 +24,9 @@ private final class RecentSessionsControllerArguments {
|
||||
|
||||
let addDevice: () -> Void
|
||||
|
||||
init(account: Account, setSessionIdWithRevealedOptions: @escaping (Int64?, Int64?) -> Void, removeSession: @escaping (Int64) -> Void, terminateOtherSessions: @escaping () -> Void, removeWebSession: @escaping (Int64) -> Void, terminateAllWebSessions: @escaping () -> Void, addDevice: @escaping () -> Void) {
|
||||
let openOtherAppsUrl: () -> Void
|
||||
|
||||
init(account: Account, setSessionIdWithRevealedOptions: @escaping (Int64?, Int64?) -> Void, removeSession: @escaping (Int64) -> Void, terminateOtherSessions: @escaping () -> Void, removeWebSession: @escaping (Int64) -> Void, terminateAllWebSessions: @escaping () -> Void, addDevice: @escaping () -> Void, openOtherAppsUrl: @escaping () -> Void) {
|
||||
self.account = account
|
||||
self.setSessionIdWithRevealedOptions = setSessionIdWithRevealedOptions
|
||||
self.removeSession = removeSession
|
||||
@ -34,6 +36,8 @@ private final class RecentSessionsControllerArguments {
|
||||
self.terminateAllWebSessions = terminateAllWebSessions
|
||||
|
||||
self.addDevice = addDevice
|
||||
|
||||
self.openOtherAppsUrl = openOtherAppsUrl
|
||||
}
|
||||
}
|
||||
|
||||
@ -51,32 +55,7 @@ private enum RecentSessionsSection: Int32 {
|
||||
private enum RecentSessionsEntryStableId: Hashable {
|
||||
case session(Int64)
|
||||
case index(Int32)
|
||||
|
||||
var hashValue: Int {
|
||||
switch self {
|
||||
case let .session(hash):
|
||||
return hash.hashValue
|
||||
case let .index(index):
|
||||
return index.hashValue
|
||||
}
|
||||
}
|
||||
|
||||
static func ==(lhs: RecentSessionsEntryStableId, rhs: RecentSessionsEntryStableId) -> Bool {
|
||||
switch lhs {
|
||||
case let .session(hash):
|
||||
if case .session(hash) = rhs {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .index(index):
|
||||
if case .index(index) = rhs {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
case devicesInfo
|
||||
}
|
||||
|
||||
private enum RecentSessionsEntry: ItemListNodeEntry {
|
||||
@ -92,215 +71,243 @@ private enum RecentSessionsEntry: ItemListNodeEntry {
|
||||
case addDevice(PresentationTheme, String)
|
||||
case session(index: Int32, theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, session: RecentAccountSession, enabled: Bool, editing: Bool, revealed: Bool)
|
||||
case website(index: Int32, theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, nameDisplayOrder: PresentationPersonNameOrder, website: WebAuthorization, peer: Peer?, enabled: Bool, editing: Bool, revealed: Bool)
|
||||
case devicesInfo(PresentationTheme, String)
|
||||
|
||||
var section: ItemListSectionId {
|
||||
switch self {
|
||||
case .currentSessionHeader, .currentSession, .terminateOtherSessions, .terminateAllWebSessions, .currentSessionInfo:
|
||||
return RecentSessionsSection.currentSession.rawValue
|
||||
case .pendingSessionsHeader, .pendingSession, .pendingSessionsInfo:
|
||||
return RecentSessionsSection.pendingSessions.rawValue
|
||||
case .otherSessionsHeader, .addDevice, .session, .website:
|
||||
return RecentSessionsSection.otherSessions.rawValue
|
||||
case .currentSessionHeader, .currentSession, .terminateOtherSessions, .terminateAllWebSessions, .currentSessionInfo:
|
||||
return RecentSessionsSection.currentSession.rawValue
|
||||
case .pendingSessionsHeader, .pendingSession, .pendingSessionsInfo:
|
||||
return RecentSessionsSection.pendingSessions.rawValue
|
||||
case .otherSessionsHeader, .addDevice, .session, .website, .devicesInfo:
|
||||
return RecentSessionsSection.otherSessions.rawValue
|
||||
}
|
||||
}
|
||||
|
||||
var stableId: RecentSessionsEntryStableId {
|
||||
switch self {
|
||||
case .currentSessionHeader:
|
||||
return .index(0)
|
||||
case .currentSession:
|
||||
return .index(1)
|
||||
case .terminateOtherSessions:
|
||||
return .index(2)
|
||||
case .terminateAllWebSessions:
|
||||
return .index(3)
|
||||
case .currentSessionInfo:
|
||||
return .index(4)
|
||||
case .pendingSessionsHeader:
|
||||
return .index(5)
|
||||
case let .pendingSession(_, _, _, _, session, _, _, _):
|
||||
return .session(session.hash)
|
||||
case .pendingSessionsInfo:
|
||||
return .index(6)
|
||||
case .otherSessionsHeader:
|
||||
return .index(7)
|
||||
case .addDevice:
|
||||
return .index(8)
|
||||
case let .session(_, _, _, _, session, _, _, _):
|
||||
return .session(session.hash)
|
||||
case let .website(_, _, _, _, _, website, _, _, _, _):
|
||||
return .session(website.hash)
|
||||
case .currentSessionHeader:
|
||||
return .index(0)
|
||||
case .currentSession:
|
||||
return .index(1)
|
||||
case .terminateOtherSessions:
|
||||
return .index(2)
|
||||
case .terminateAllWebSessions:
|
||||
return .index(3)
|
||||
case .currentSessionInfo:
|
||||
return .index(4)
|
||||
case .pendingSessionsHeader:
|
||||
return .index(5)
|
||||
case let .pendingSession(_, _, _, _, session, _, _, _):
|
||||
return .session(session.hash)
|
||||
case .pendingSessionsInfo:
|
||||
return .index(6)
|
||||
case .otherSessionsHeader:
|
||||
return .index(7)
|
||||
case .addDevice:
|
||||
return .index(8)
|
||||
case let .session(_, _, _, _, session, _, _, _):
|
||||
return .session(session.hash)
|
||||
case let .website(_, _, _, _, _, website, _, _, _, _):
|
||||
return .session(website.hash)
|
||||
case .devicesInfo:
|
||||
return .devicesInfo
|
||||
}
|
||||
}
|
||||
|
||||
static func ==(lhs: RecentSessionsEntry, rhs: RecentSessionsEntry) -> Bool {
|
||||
switch lhs {
|
||||
case let .currentSessionHeader(lhsTheme, lhsText):
|
||||
if case let .currentSessionHeader(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .terminateOtherSessions(lhsTheme, lhsText):
|
||||
if case let .terminateOtherSessions(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .terminateAllWebSessions(lhsTheme, lhsText):
|
||||
if case let .terminateAllWebSessions(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .currentSessionInfo(lhsTheme, lhsText):
|
||||
if case let .currentSessionInfo(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .pendingSessionsHeader(lhsTheme, lhsText):
|
||||
if case let .pendingSessionsHeader(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .pendingSession(lhsIndex, lhsTheme, lhsStrings, lhsDateTimeFormat, lhsSession, lhsEnabled, lhsEditing, lhsRevealed):
|
||||
if case let .pendingSession(rhsIndex, rhsTheme, rhsStrings, rhsDateTimeFormat, rhsSession, rhsEnabled, rhsEditing, rhsRevealed) = rhs, lhsIndex == rhsIndex, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsDateTimeFormat == rhsDateTimeFormat, lhsSession == rhsSession, lhsEnabled == rhsEnabled, lhsEditing == rhsEditing, lhsRevealed == rhsRevealed {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .pendingSessionsInfo(lhsTheme, lhsText):
|
||||
if case let .pendingSessionsInfo(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .otherSessionsHeader(lhsTheme, lhsText):
|
||||
if case let .otherSessionsHeader(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .addDevice(lhsTheme, lhsText):
|
||||
if case let .addDevice(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .currentSession(lhsTheme, lhsStrings, lhsDateTimeFormat, lhsSession):
|
||||
if case let .currentSession(rhsTheme, rhsStrings, rhsDateTimeFormat, rhsSession) = rhs, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsDateTimeFormat == rhsDateTimeFormat, lhsSession == rhsSession {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .session(lhsIndex, lhsTheme, lhsStrings, lhsDateTimeFormat, lhsSession, lhsEnabled, lhsEditing, lhsRevealed):
|
||||
if case let .session(rhsIndex, rhsTheme, rhsStrings, rhsDateTimeFormat, rhsSession, rhsEnabled, rhsEditing, rhsRevealed) = rhs, lhsIndex == rhsIndex, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsDateTimeFormat == rhsDateTimeFormat, lhsSession == rhsSession, lhsEnabled == rhsEnabled, lhsEditing == rhsEditing, lhsRevealed == rhsRevealed {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .website(lhsIndex, lhsTheme, lhsStrings, lhsDateTimeFormat, lhsNameOrder, lhsWebsite, lhsPeer, lhsEnabled, lhsEditing, lhsRevealed):
|
||||
if case let .website(rhsIndex, rhsTheme, rhsStrings, rhsDateTimeFormat, rhsNameOrder, rhsWebsite, rhsPeer, rhsEnabled, rhsEditing, rhsRevealed) = rhs, lhsIndex == rhsIndex, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsDateTimeFormat == rhsDateTimeFormat, lhsNameOrder == rhsNameOrder, lhsWebsite == rhsWebsite, arePeersEqual(lhsPeer, rhsPeer), lhsEnabled == rhsEnabled, lhsEditing == rhsEditing, lhsRevealed == rhsRevealed {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .currentSessionHeader(lhsTheme, lhsText):
|
||||
if case let .currentSessionHeader(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .terminateOtherSessions(lhsTheme, lhsText):
|
||||
if case let .terminateOtherSessions(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .terminateAllWebSessions(lhsTheme, lhsText):
|
||||
if case let .terminateAllWebSessions(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .currentSessionInfo(lhsTheme, lhsText):
|
||||
if case let .currentSessionInfo(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .pendingSessionsHeader(lhsTheme, lhsText):
|
||||
if case let .pendingSessionsHeader(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .pendingSession(lhsIndex, lhsTheme, lhsStrings, lhsDateTimeFormat, lhsSession, lhsEnabled, lhsEditing, lhsRevealed):
|
||||
if case let .pendingSession(rhsIndex, rhsTheme, rhsStrings, rhsDateTimeFormat, rhsSession, rhsEnabled, rhsEditing, rhsRevealed) = rhs, lhsIndex == rhsIndex, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsDateTimeFormat == rhsDateTimeFormat, lhsSession == rhsSession, lhsEnabled == rhsEnabled, lhsEditing == rhsEditing, lhsRevealed == rhsRevealed {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .pendingSessionsInfo(lhsTheme, lhsText):
|
||||
if case let .pendingSessionsInfo(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .otherSessionsHeader(lhsTheme, lhsText):
|
||||
if case let .otherSessionsHeader(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .addDevice(lhsTheme, lhsText):
|
||||
if case let .addDevice(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .currentSession(lhsTheme, lhsStrings, lhsDateTimeFormat, lhsSession):
|
||||
if case let .currentSession(rhsTheme, rhsStrings, rhsDateTimeFormat, rhsSession) = rhs, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsDateTimeFormat == rhsDateTimeFormat, lhsSession == rhsSession {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .session(lhsIndex, lhsTheme, lhsStrings, lhsDateTimeFormat, lhsSession, lhsEnabled, lhsEditing, lhsRevealed):
|
||||
if case let .session(rhsIndex, rhsTheme, rhsStrings, rhsDateTimeFormat, rhsSession, rhsEnabled, rhsEditing, rhsRevealed) = rhs, lhsIndex == rhsIndex, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsDateTimeFormat == rhsDateTimeFormat, lhsSession == rhsSession, lhsEnabled == rhsEnabled, lhsEditing == rhsEditing, lhsRevealed == rhsRevealed {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .website(lhsIndex, lhsTheme, lhsStrings, lhsDateTimeFormat, lhsNameOrder, lhsWebsite, lhsPeer, lhsEnabled, lhsEditing, lhsRevealed):
|
||||
if case let .website(rhsIndex, rhsTheme, rhsStrings, rhsDateTimeFormat, rhsNameOrder, rhsWebsite, rhsPeer, rhsEnabled, rhsEditing, rhsRevealed) = rhs, lhsIndex == rhsIndex, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsDateTimeFormat == rhsDateTimeFormat, lhsNameOrder == rhsNameOrder, lhsWebsite == rhsWebsite, arePeersEqual(lhsPeer, rhsPeer), lhsEnabled == rhsEnabled, lhsEditing == rhsEditing, lhsRevealed == rhsRevealed {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .devicesInfo(lhsTheme, lhsText):
|
||||
if case let .devicesInfo(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static func <(lhs: RecentSessionsEntry, rhs: RecentSessionsEntry) -> Bool {
|
||||
switch lhs.stableId {
|
||||
case let .index(lhsIndex):
|
||||
if case let .index(rhsIndex) = rhs.stableId {
|
||||
return lhsIndex <= rhsIndex
|
||||
case let .index(lhsIndex):
|
||||
if case let .index(rhsIndex) = rhs.stableId {
|
||||
return lhsIndex <= rhsIndex
|
||||
} else {
|
||||
if case .pendingSession = rhs, lhsIndex > 5 {
|
||||
return false
|
||||
} else {
|
||||
if case .pendingSession = rhs, lhsIndex > 5 {
|
||||
return false
|
||||
return true
|
||||
}
|
||||
}
|
||||
case .session:
|
||||
switch lhs {
|
||||
case let .session(lhsIndex, _, _, _, _, _, _, _):
|
||||
if case let .session(rhsIndex, _, _, _, _, _, _, _) = rhs {
|
||||
return lhsIndex <= rhsIndex
|
||||
} else if case .devicesInfo = rhs.stableId {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .pendingSession(lhsIndex, _, _, _, _, _, _, _):
|
||||
if case let .pendingSession(rhsIndex, _, _, _, _, _, _, _) = rhs {
|
||||
return lhsIndex <= rhsIndex
|
||||
} else if case .session = rhs {
|
||||
return true
|
||||
} else if case .devicesInfo = rhs.stableId {
|
||||
return true
|
||||
} else {
|
||||
if case let .index(rhsIndex) = rhs.stableId {
|
||||
return rhsIndex == 6
|
||||
} else {
|
||||
return true
|
||||
return false
|
||||
}
|
||||
}
|
||||
case .session:
|
||||
switch lhs {
|
||||
case let .session(lhsIndex, _, _, _, _, _, _, _):
|
||||
if case let .session(rhsIndex, _, _, _, _, _, _, _) = rhs {
|
||||
return lhsIndex <= rhsIndex
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .pendingSession(lhsIndex, _, _, _, _, _, _, _):
|
||||
if case let .pendingSession(rhsIndex, _, _, _, _, _, _, _) = rhs {
|
||||
return lhsIndex <= rhsIndex
|
||||
} else if case .session = rhs {
|
||||
return true
|
||||
} else {
|
||||
if case let .index(rhsIndex) = rhs.stableId {
|
||||
return rhsIndex == 6
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
case let .website(lhsIndex, _, _, _, _, _, _, _, _, _):
|
||||
if case let .website(rhsIndex, _, _, _, _, _, _, _, _, _) = rhs {
|
||||
return lhsIndex <= rhsIndex
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
default:
|
||||
preconditionFailure()
|
||||
case let .website(lhsIndex, _, _, _, _, _, _, _, _, _):
|
||||
if case let .website(rhsIndex, _, _, _, _, _, _, _, _, _) = rhs {
|
||||
return lhsIndex <= rhsIndex
|
||||
} else if case .devicesInfo = rhs.stableId {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
default:
|
||||
preconditionFailure()
|
||||
}
|
||||
case .devicesInfo:
|
||||
if case .devicesInfo = rhs.stableId {
|
||||
return false
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func item(presentationData: ItemListPresentationData, arguments: Any) -> ListViewItem {
|
||||
let arguments = arguments as! RecentSessionsControllerArguments
|
||||
switch self {
|
||||
case let .currentSessionHeader(theme, text):
|
||||
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
|
||||
case let .currentSession(theme, strings, dateTimeFormat, session):
|
||||
return ItemListRecentSessionItem(presentationData: presentationData, dateTimeFormat: dateTimeFormat, session: session, enabled: true, editable: false, editing: false, revealed: false, sectionId: self.section, setSessionIdWithRevealedOptions: { _, _ in
|
||||
}, removeSession: { _ in
|
||||
})
|
||||
case let .terminateOtherSessions(theme, text):
|
||||
return ItemListActionItem(presentationData: presentationData, title: text, kind: .destructive, alignment: .natural, sectionId: self.section, style: .blocks, action: {
|
||||
arguments.terminateOtherSessions()
|
||||
})
|
||||
case let .terminateAllWebSessions(theme, text):
|
||||
return ItemListActionItem(presentationData: presentationData, title: text, kind: .destructive, alignment: .natural, sectionId: self.section, style: .blocks, action: {
|
||||
arguments.terminateAllWebSessions()
|
||||
})
|
||||
case let .currentSessionInfo(theme, text):
|
||||
return ItemListTextItem(presentationData: presentationData, text: .plain(text), sectionId: self.section)
|
||||
case let .pendingSessionsHeader(theme, text):
|
||||
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
|
||||
case let .pendingSession(_, theme, strings, dateTimeFormat, session, enabled, editing, revealed):
|
||||
return ItemListRecentSessionItem(presentationData: presentationData, dateTimeFormat: dateTimeFormat, session: session, enabled: enabled, editable: true, editing: editing, revealed: revealed, sectionId: self.section, setSessionIdWithRevealedOptions: { previousId, id in
|
||||
arguments.setSessionIdWithRevealedOptions(previousId, id)
|
||||
}, removeSession: { id in
|
||||
arguments.removeSession(id)
|
||||
})
|
||||
case let .pendingSessionsInfo(theme, text):
|
||||
return ItemListTextItem(presentationData: presentationData, text: .plain(text), sectionId: self.section)
|
||||
case let .otherSessionsHeader(theme, text):
|
||||
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
|
||||
case let .addDevice(theme, text):
|
||||
return ItemListActionItem(presentationData: presentationData, title: text, kind: .generic, alignment: .natural, sectionId: self.section, style: .blocks, action: {
|
||||
arguments.addDevice()
|
||||
})
|
||||
case let .session(_, theme, strings, dateTimeFormat, session, enabled, editing, revealed):
|
||||
return ItemListRecentSessionItem(presentationData: presentationData, dateTimeFormat: dateTimeFormat, session: session, enabled: enabled, editable: true, editing: editing, revealed: revealed, sectionId: self.section, setSessionIdWithRevealedOptions: { previousId, id in
|
||||
arguments.setSessionIdWithRevealedOptions(previousId, id)
|
||||
}, removeSession: { id in
|
||||
arguments.removeSession(id)
|
||||
})
|
||||
case let .website(_, theme, strings, dateTimeFormat, nameDisplayOrder, website, peer, enabled, editing, revealed):
|
||||
return ItemListWebsiteItem(account: arguments.account, theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, website: website, peer: peer, enabled: enabled, editing: editing, revealed: revealed, sectionId: self.section, setSessionIdWithRevealedOptions: { previousId, id in
|
||||
arguments.setSessionIdWithRevealedOptions(previousId, id)
|
||||
}, removeSession: { id in
|
||||
arguments.removeWebSession(id)
|
||||
})
|
||||
case let .currentSessionHeader(theme, text):
|
||||
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
|
||||
case let .currentSession(theme, strings, dateTimeFormat, session):
|
||||
return ItemListRecentSessionItem(presentationData: presentationData, dateTimeFormat: dateTimeFormat, session: session, enabled: true, editable: false, editing: false, revealed: false, sectionId: self.section, setSessionIdWithRevealedOptions: { _, _ in
|
||||
}, removeSession: { _ in
|
||||
})
|
||||
case let .terminateOtherSessions(theme, text):
|
||||
return ItemListActionItem(presentationData: presentationData, title: text, kind: .destructive, alignment: .natural, sectionId: self.section, style: .blocks, action: {
|
||||
arguments.terminateOtherSessions()
|
||||
})
|
||||
case let .terminateAllWebSessions(theme, text):
|
||||
return ItemListActionItem(presentationData: presentationData, title: text, kind: .destructive, alignment: .natural, sectionId: self.section, style: .blocks, action: {
|
||||
arguments.terminateAllWebSessions()
|
||||
})
|
||||
case let .currentSessionInfo(theme, text):
|
||||
return ItemListTextItem(presentationData: presentationData, text: .plain(text), sectionId: self.section)
|
||||
case let .pendingSessionsHeader(theme, text):
|
||||
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
|
||||
case let .pendingSession(_, theme, strings, dateTimeFormat, session, enabled, editing, revealed):
|
||||
return ItemListRecentSessionItem(presentationData: presentationData, dateTimeFormat: dateTimeFormat, session: session, enabled: enabled, editable: true, editing: editing, revealed: revealed, sectionId: self.section, setSessionIdWithRevealedOptions: { previousId, id in
|
||||
arguments.setSessionIdWithRevealedOptions(previousId, id)
|
||||
}, removeSession: { id in
|
||||
arguments.removeSession(id)
|
||||
})
|
||||
case let .pendingSessionsInfo(theme, text):
|
||||
return ItemListTextItem(presentationData: presentationData, text: .plain(text), sectionId: self.section)
|
||||
case let .otherSessionsHeader(theme, text):
|
||||
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
|
||||
case let .addDevice(theme, text):
|
||||
return ItemListActionItem(presentationData: presentationData, title: text, kind: .generic, alignment: .natural, sectionId: self.section, style: .blocks, action: {
|
||||
arguments.addDevice()
|
||||
})
|
||||
case let .session(_, theme, strings, dateTimeFormat, session, enabled, editing, revealed):
|
||||
return ItemListRecentSessionItem(presentationData: presentationData, dateTimeFormat: dateTimeFormat, session: session, enabled: enabled, editable: true, editing: editing, revealed: revealed, sectionId: self.section, setSessionIdWithRevealedOptions: { previousId, id in
|
||||
arguments.setSessionIdWithRevealedOptions(previousId, id)
|
||||
}, removeSession: { id in
|
||||
arguments.removeSession(id)
|
||||
})
|
||||
case let .website(_, theme, strings, dateTimeFormat, nameDisplayOrder, website, peer, enabled, editing, revealed):
|
||||
return ItemListWebsiteItem(account: arguments.account, theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, website: website, peer: peer, enabled: enabled, editing: editing, revealed: revealed, sectionId: self.section, setSessionIdWithRevealedOptions: { previousId, id in
|
||||
arguments.setSessionIdWithRevealedOptions(previousId, id)
|
||||
}, removeSession: { id in
|
||||
arguments.removeWebSession(id)
|
||||
})
|
||||
case let .devicesInfo(theme, text):
|
||||
return ItemListTextItem(presentationData: presentationData, text: .markdown(text), sectionId: self.section, linkAction: { action in
|
||||
switch action {
|
||||
case .tap:
|
||||
arguments.openOtherAppsUrl()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -402,6 +409,10 @@ private func recentSessionsControllerEntries(presentationData: PresentationData,
|
||||
entries.append(.session(index: Int32(i), theme: presentationData.theme, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, session: filteredSessions[i], enabled: state.removingSessionId != filteredSessions[i].hash && !state.terminatingOtherSessions, editing: state.editing, revealed: state.sessionIdWithRevealedOptions == filteredSessions[i].hash))
|
||||
}
|
||||
}
|
||||
|
||||
if enableQRLogin {
|
||||
entries.append(.devicesInfo(presentationData.theme, presentationData.strings.AuthSessions_OtherDevices))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -601,7 +612,9 @@ public func recentSessionsController(context: AccountContext, activeSessionsCont
|
||||
])
|
||||
presentControllerImpl?(controller, ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
||||
}, addDevice: {
|
||||
pushControllerImpl?(AuthTransferScanScreen(context: context, activeSessionsContext: activeSessionsContext))
|
||||
pushControllerImpl?(AuthDataTransferSplashScreen(context: context, activeSessionsContext: activeSessionsContext))
|
||||
}, openOtherAppsUrl: {
|
||||
context.sharedContext.openExternalUrl(context: context, urlContext: .generic, url: "https://telegram.org/desktop", forceExternal: true, presentationData: context.sharedContext.currentPresentationData.with { $0 }, navigationController: nil, dismissInput: {})
|
||||
})
|
||||
|
||||
let websitesSignal: Signal<([WebAuthorization], [PeerId : Peer])?, NoError> = .single(nil) |> then(webSessions(network: context.account.network) |> map(Optional.init))
|
||||
|
@ -213,6 +213,7 @@ private indirect enum SettingsEntry: ItemListNodeEntry {
|
||||
case savedMessages(PresentationTheme, UIImage?, String)
|
||||
case recentCalls(PresentationTheme, UIImage?, String)
|
||||
case stickers(PresentationTheme, UIImage?, String, String, [ArchivedStickerPackItem]?)
|
||||
case contentStickers(PresentationTheme, UIImage?, String, String, [ArchivedStickerPackItem]?)
|
||||
|
||||
case notificationsAndSounds(PresentationTheme, UIImage?, String, NotificationExceptionsList?, Bool)
|
||||
case privacyAndSecurity(PresentationTheme, UIImage?, String, AccountPrivacySettings?)
|
||||
@ -240,7 +241,7 @@ private indirect enum SettingsEntry: ItemListNodeEntry {
|
||||
return SettingsSection.media.rawValue
|
||||
case .savedMessages, .recentCalls, .stickers:
|
||||
return SettingsSection.media.rawValue
|
||||
case .notificationsAndSounds, .privacyAndSecurity, .dataAndStorage, .themes, .language:
|
||||
case .notificationsAndSounds, .privacyAndSecurity, .dataAndStorage, .themes, .language, .contentStickers:
|
||||
return SettingsSection.generalSettings.rawValue
|
||||
case .passport, .wallet, .watch :
|
||||
return SettingsSection.advanced.rawValue
|
||||
@ -287,16 +288,18 @@ private indirect enum SettingsEntry: ItemListNodeEntry {
|
||||
return 1011
|
||||
case .language:
|
||||
return 1012
|
||||
case .wallet:
|
||||
case .contentStickers:
|
||||
return 1013
|
||||
case .passport:
|
||||
case .wallet:
|
||||
return 1014
|
||||
case .watch:
|
||||
case .passport:
|
||||
return 1015
|
||||
case .askAQuestion:
|
||||
case .watch:
|
||||
return 1016
|
||||
case .faq:
|
||||
case .askAQuestion:
|
||||
return 1017
|
||||
case .faq:
|
||||
return 1018
|
||||
}
|
||||
}
|
||||
|
||||
@ -412,6 +415,12 @@ private indirect enum SettingsEntry: ItemListNodeEntry {
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .contentStickers(lhsTheme, lhsImage, lhsText, lhsValue, _):
|
||||
if case let .contentStickers(rhsTheme, rhsImage, rhsText, rhsValue, _) = rhs, lhsTheme === rhsTheme, lhsImage === rhsImage, lhsText == rhsText, lhsValue == rhsValue {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .notificationsAndSounds(lhsTheme, lhsImage, lhsText, lhsExceptionsList, lhsWarning):
|
||||
if case let .notificationsAndSounds(rhsTheme, rhsImage, rhsText, rhsExceptionsList, rhsWarning) = rhs, lhsTheme === rhsTheme, lhsImage === rhsImage, lhsText == rhsText, lhsExceptionsList == rhsExceptionsList, lhsWarning == rhsWarning {
|
||||
return true
|
||||
@ -559,6 +568,10 @@ private indirect enum SettingsEntry: ItemListNodeEntry {
|
||||
return ItemListDisclosureItem(presentationData: presentationData, icon: image, title: text, label: value, labelStyle: .badge(theme.list.itemAccentColor), sectionId: ItemListSectionId(self.section), style: .blocks, action: {
|
||||
arguments.openStickerPacks(archivedPacks)
|
||||
}, clearHighlightAutomatically: false)
|
||||
case let .contentStickers(theme, image, text, value, archivedPacks):
|
||||
return ItemListDisclosureItem(presentationData: presentationData, icon: image, title: text, label: value, labelStyle: .badge(theme.list.itemAccentColor), sectionId: ItemListSectionId(self.section), style: .blocks, action: {
|
||||
arguments.openStickerPacks(archivedPacks)
|
||||
}, clearHighlightAutomatically: false)
|
||||
case let .notificationsAndSounds(theme, image, text, exceptionsList, warning):
|
||||
return ItemListDisclosureItem(presentationData: presentationData, icon: image, title: text, label: warning ? "!" : "", labelStyle: warning ? .badge(theme.list.itemDestructiveColor) : .text, sectionId: ItemListSectionId(self.section), style: .blocks, action: {
|
||||
arguments.openNotificationsAndSounds(exceptionsList)
|
||||
@ -657,9 +670,10 @@ private func settingsEntries(account: Account, presentationData: PresentationDat
|
||||
|
||||
entries.append(.savedMessages(presentationData.theme, PresentationResourcesSettings.savedMessages, presentationData.strings.Settings_SavedMessages))
|
||||
entries.append(.recentCalls(presentationData.theme, PresentationResourcesSettings.recentCalls, presentationData.strings.CallSettings_RecentCalls))
|
||||
entries.append(.stickers(presentationData.theme, PresentationResourcesSettings.stickers, presentationData.strings.ChatSettings_Stickers, unreadTrendingStickerPacks == 0 ? "" : "\(unreadTrendingStickerPacks)", archivedPacks))
|
||||
if enableQRLogin {
|
||||
entries.append(.devices(presentationData.theme, UIImage(bundleImageName: "Settings/MenuIcons/Sessions")?.precomposed(), presentationData.strings.Settings_Devices, otherSessionCount == 0 ? presentationData.strings.Settings_AddDevice : "\(otherSessionCount)"))
|
||||
} else {
|
||||
entries.append(.stickers(presentationData.theme, PresentationResourcesSettings.stickers, presentationData.strings.ChatSettings_Stickers, unreadTrendingStickerPacks == 0 ? "" : "\(unreadTrendingStickerPacks)", archivedPacks))
|
||||
}
|
||||
|
||||
let notificationsWarning = shouldDisplayNotificationsPermissionWarning(status: notificationsAuthorizationStatus, suppressed: notificationsWarningSuppressed)
|
||||
@ -669,6 +683,9 @@ private func settingsEntries(account: Account, presentationData: PresentationDat
|
||||
entries.append(.themes(presentationData.theme, PresentationResourcesSettings.appearance, presentationData.strings.Settings_Appearance))
|
||||
let languageName = presentationData.strings.primaryComponent.localizedName
|
||||
entries.append(.language(presentationData.theme, PresentationResourcesSettings.language, presentationData.strings.Settings_AppLanguage, languageName.isEmpty ? presentationData.strings.Localization_LanguageName : languageName))
|
||||
if enableQRLogin {
|
||||
entries.append(.contentStickers(presentationData.theme, PresentationResourcesSettings.stickers, presentationData.strings.ChatSettings_Stickers, unreadTrendingStickerPacks == 0 ? "" : "\(unreadTrendingStickerPacks)", archivedPacks))
|
||||
}
|
||||
|
||||
if hasWallet {
|
||||
entries.append(.wallet(presentationData.theme, PresentationResourcesSettings.wallet, "Gram Wallet", ""))
|
||||
@ -1093,7 +1110,7 @@ public func settingsController(context: AccountContext, accountManager: AccountM
|
||||
|> deliverOnMainQueue
|
||||
|> take(1)).start(next: { activeSessionsContext, count in
|
||||
if count == 0 {
|
||||
pushControllerImpl?(AuthTransferScanScreen(context: context, activeSessionsContext: activeSessionsContext))
|
||||
pushControllerImpl?(AuthDataTransferSplashScreen(context: context, activeSessionsContext: activeSessionsContext))
|
||||
} else {
|
||||
pushControllerImpl?(recentSessionsController(context: context, activeSessionsContext: activeSessionsContext))
|
||||
}
|
||||
|
@ -319,9 +319,9 @@ final class ChatHistoryPreloadManager {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
#if DEBUG
|
||||
/*#if DEBUG
|
||||
return
|
||||
#endif
|
||||
#endif*/
|
||||
|
||||
var indices: [(ChatHistoryPreloadIndex, Bool, Bool)] = []
|
||||
for entry in view.0.entries {
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -59,4 +59,6 @@ public struct PresentationResourcesSettings {
|
||||
public static let setPasscode = renderIcon(name: "Settings/MenuIcons/SetPasscode")
|
||||
public static let clearCache = renderIcon(name: "Settings/MenuIcons/ClearCache")
|
||||
public static let changePhoneNumber = renderIcon(name: "Settings/MenuIcons/ChangePhoneNumber")
|
||||
|
||||
public static let websites = renderIcon(name: "Settings/MenuIcons/Websites")
|
||||
}
|
||||
|
22
submodules/TelegramUI/Images.xcassets/Settings/MenuIcons/Websites.imageset/Contents.json
vendored
Normal file
22
submodules/TelegramUI/Images.xcassets/Settings/MenuIcons/Websites.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "ic_activewebsites@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "ic_activewebsites@3x.png",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
BIN
submodules/TelegramUI/Images.xcassets/Settings/MenuIcons/Websites.imageset/ic_activewebsites@2x.png
vendored
Normal file
BIN
submodules/TelegramUI/Images.xcassets/Settings/MenuIcons/Websites.imageset/ic_activewebsites@2x.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.3 KiB |
BIN
submodules/TelegramUI/Images.xcassets/Settings/MenuIcons/Websites.imageset/ic_activewebsites@3x.png
vendored
Normal file
BIN
submodules/TelegramUI/Images.xcassets/Settings/MenuIcons/Websites.imageset/ic_activewebsites@3x.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.9 KiB |
@ -152,6 +152,9 @@ final class HorizontalStickersChatContextPanelNode: ChatInputContextPanelNode {
|
||||
override func didLoad() {
|
||||
super.didLoad()
|
||||
|
||||
self.gridNode.view.disablesInteractiveTransitionGestureRecognizer = true
|
||||
self.gridNode.view.disablesInteractiveKeyboardGestureRecognizer = true
|
||||
|
||||
self.view.addGestureRecognizer(PeekControllerGestureRecognizer(contentAtPoint: { [weak self] point in
|
||||
if let strongSelf = self {
|
||||
let convertedPoint = strongSelf.gridNode.view.convert(point, from: strongSelf.view)
|
||||
|
File diff suppressed because one or more lines are too long
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user