diff --git a/Telegram/Telegram-iOS/en.lproj/Localizable.strings b/Telegram/Telegram-iOS/en.lproj/Localizable.strings index 827bfd95db..6be671610b 100644 --- a/Telegram/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram/Telegram-iOS/en.lproj/Localizable.strings @@ -7441,6 +7441,7 @@ Sorry for the inconvenience."; "WebApp.AddToAttachmentUnavailableError" = "This bot can't be added to the attachment menu."; "WebApp.AddToAttachmentAlreadyAddedError" = "This bot is already added to your attachment menu."; +"WebApp.AddToAttachmentSucceeded" = "**%@** has been added to your attachment menu."; "WebApp.OpenWebViewAlertTitle" = "Open Web App"; "WebApp.OpenWebViewAlertText" = "**%@** would like to open its web app to proceed.\n\nIt will be able to access your **IP address** and basic device info."; @@ -7968,4 +7969,6 @@ Sorry for the inconvenience."; "Login.Edit" = "Edit"; "Login.Yes" = "Yes"; +"Checkout.PaymentLiabilityBothAlert" = "Telegram will not have access to your credit card information. Credit card details will be handled only by the payment system, {target}.\n\nPayments will go directly to the developer of {target}. Telegram cannot provide any guarantees, so proceed at your own risk. In case of problems, please contact the developer of {target} or your bank."; + "Settings.ChangeProfilePhoto" = "Change Profile Photo"; diff --git a/submodules/AccountContext/Sources/ChatController.swift b/submodules/AccountContext/Sources/ChatController.swift index dec3611c54..ddfa955e50 100644 --- a/submodules/AccountContext/Sources/ChatController.swift +++ b/submodules/AccountContext/Sources/ChatController.swift @@ -151,10 +151,12 @@ public struct ChatControllerInitialBotStart { public struct ChatControllerInitialAttachBotStart { public let botId: PeerId public let payload: String? + public let justInstalled: Bool - public init(botId: PeerId, payload: String?) { + public init(botId: PeerId, payload: String?, justInstalled: Bool) { self.botId = botId self.payload = payload + self.justInstalled = justInstalled } } diff --git a/submodules/AuthorizationUI/Sources/AuthorizationLayout.swift b/submodules/AuthorizationUI/Sources/AuthorizationLayout.swift index 1fddcb52e4..2ed4c8a44f 100644 --- a/submodules/AuthorizationUI/Sources/AuthorizationLayout.swift +++ b/submodules/AuthorizationUI/Sources/AuthorizationLayout.swift @@ -14,7 +14,8 @@ public struct AuthorizationLayoutItemSpacing { } public struct AuthorizationLayoutItem { - public var node: ASDisplayNode + public var node: ASDisplayNode? + public var view: UIView? public var size: CGSize public var spacingBefore: AuthorizationLayoutItemSpacing public var spacingAfter: AuthorizationLayoutItemSpacing @@ -25,6 +26,14 @@ public struct AuthorizationLayoutItem { self.spacingBefore = spacingBefore self.spacingAfter = spacingAfter } + + + public init(view: UIView, size: CGSize, spacingBefore: AuthorizationLayoutItemSpacing, spacingAfter: AuthorizationLayoutItemSpacing) { + self.view = view + self.size = size + self.spacingBefore = spacingBefore + self.spacingAfter = spacingAfter + } } public final class SolvedAuthorizationLayoutItem { @@ -147,7 +156,12 @@ public func layoutAuthorizationItems(bounds: CGRect, items: [AuthorizationLayout for i in 0 ..< solvedItems.count { let item = solvedItems[i] verticalOrigin += item.spacingBefore! - transition.updateFrame(node: item.item.node, frame: CGRect(origin: CGPoint(x: floor((bounds.size.width - item.item.size.width) / 2.0), y: verticalOrigin), size: item.item.size)) + let itemFrame = CGRect(origin: CGPoint(x: floor((bounds.size.width - item.item.size.width) / 2.0), y: verticalOrigin), size: item.item.size) + if let view = item.item.view { + transition.updateFrame(view: view, frame: itemFrame) + } else if let node = item.item.node { + transition.updateFrame(node: node, frame: itemFrame) + } verticalOrigin += item.item.size.height verticalOrigin += item.spacingAfter! } diff --git a/submodules/BotPaymentsUI/Sources/BotCheckoutControllerNode.swift b/submodules/BotPaymentsUI/Sources/BotCheckoutControllerNode.swift index 17c73da3c7..5e33e8e693 100644 --- a/submodules/BotPaymentsUI/Sources/BotCheckoutControllerNode.swift +++ b/submodules/BotPaymentsUI/Sources/BotCheckoutControllerNode.swift @@ -1464,10 +1464,16 @@ final class BotCheckoutControllerNode: ItemListControllerNode, PKPaymentAuthoriz if value { strongSelf.pay(savedCredentialsToken: savedCredentialsToken, liabilityNoticeAccepted: true) } else { - let paymentText = strongSelf.presentationData.strings.Checkout_PaymentLiabilityAlert + let paymentText: String + if botPeer.id == providerPeer?.id { + paymentText = strongSelf.presentationData.strings.Checkout_PaymentLiabilityBothAlert + .replacingOccurrences(of: "{target}", with: botPeer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)) + } else { + paymentText = strongSelf.presentationData.strings.Checkout_PaymentLiabilityAlert .replacingOccurrences(of: "{target}", with: botPeer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)) .replacingOccurrences(of: "{payment_system}", with: providerPeer?.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder) ?? "") - + } + strongSelf.present(textAlertController(context: strongSelf.context, title: strongSelf.presentationData.strings.Checkout_LiabilityAlertTitle, text: paymentText, actions: [TextAlertAction(type: .genericAction, title: strongSelf.presentationData.strings.Common_Cancel, action: { }), TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: { if let strongSelf = self { let _ = ApplicationSpecificNotice.setBotPaymentLiability(accountManager: strongSelf.context.sharedContext.accountManager, peerId: paymentForm.paymentBotId).start() diff --git a/submodules/InAppPurchaseManager/Sources/StoredTransactionState.swift b/submodules/InAppPurchaseManager/Sources/StoredTransactionState.swift deleted file mode 100644 index 3f0f328d81..0000000000 --- a/submodules/InAppPurchaseManager/Sources/StoredTransactionState.swift +++ /dev/null @@ -1,57 +0,0 @@ -//import Foundation -//import UIKit -//import SwiftSignalKit -//import Postbox -//import TelegramCore -//import TelegramUIPreferences -// -//final class StoredTransactionState: Codable { -// let timestamp: Double -// let playbackRate: AudioPlaybackRate -// -// init(timestamp: Double, playbackRate: AudioPlaybackRate) { -// self.timestamp = timestamp -// self.playbackRate = playbackRate -// } -// -// public init(from decoder: Decoder) throws { -// let container = try decoder.container(keyedBy: StringCodingKey.self) -// -// self.timestamp = try container.decode(Double.self, forKey: "timestamp") -// self.playbackRate = AudioPlaybackRate(rawValue: try container.decode(Int32.self, forKey: "playbackRate")) ?? .x1 -// } -// -// public func encode(to encoder: Encoder) throws { -// var container = encoder.container(keyedBy: StringCodingKey.self) -// -// try container.encode(self.timestamp, forKey: "timestamp") -// try container.encode(self.playbackRate.rawValue, forKey: "playbackRate") -// } -//} -// -//public func storedState(engine: TelegramEngine, : MessageId) -> Signal { -// let key = ValueBoxKey(length: 20) -// key.setInt32(0, value: messageId.namespace) -// key.setInt32(4, value: messageId.peerId.namespace._internalGetInt32Value()) -// key.setInt64(8, value: messageId.peerId.id._internalGetInt64Value()) -// key.setInt32(16, value: messageId.id) -// -// return engine.data.get(TelegramEngine.EngineData.Item.ItemCache.Item(collectionId: ApplicationSpecificItemCacheCollectionId.mediaPlaybackStoredState, id: key)) -// |> map { entry -> MediaPlaybackStoredState? in -// return entry?.get(MediaPlaybackStoredState.self) -// } -//} -// -//public func updateMediaPlaybackStoredStateInteractively(engine: TelegramEngine, messageId: MessageId, state: MediaPlaybackStoredState?) -> Signal { -// let key = ValueBoxKey(length: 20) -// key.setInt32(0, value: messageId.namespace) -// key.setInt32(4, value: messageId.peerId.namespace._internalGetInt32Value()) -// key.setInt64(8, value: messageId.peerId.id._internalGetInt64Value()) -// key.setInt32(16, value: messageId.id) -// -// if let state = state { -// return engine.itemCache.put(collectionId: ApplicationSpecificItemCacheCollectionId.mediaPlaybackStoredState, id: key, item: state) -// } else { -// return engine.itemCache.remove(collectionId: ApplicationSpecificItemCacheCollectionId.mediaPlaybackStoredState, id: key) -// } -//} diff --git a/submodules/PremiumUI/Resources/emoji.scn b/submodules/PremiumUI/Resources/emoji.scn index 26255185bd..f4f25b3ba7 100644 Binary files a/submodules/PremiumUI/Resources/emoji.scn and b/submodules/PremiumUI/Resources/emoji.scn differ diff --git a/submodules/PremiumUI/Resources/smilie.png b/submodules/PremiumUI/Resources/smilie.png index 8de30d8842..32726e505d 100644 Binary files a/submodules/PremiumUI/Resources/smilie.png and b/submodules/PremiumUI/Resources/smilie.png differ diff --git a/submodules/PremiumUI/Resources/sunglasses.png b/submodules/PremiumUI/Resources/sunglasses.png index 87f51368ba..1c0202af1d 100644 Binary files a/submodules/PremiumUI/Resources/sunglasses.png and b/submodules/PremiumUI/Resources/sunglasses.png differ diff --git a/submodules/PremiumUI/Resources/thumbsup.png b/submodules/PremiumUI/Resources/thumbsup.png index 3b13d58b2f..5279330d5a 100644 Binary files a/submodules/PremiumUI/Resources/thumbsup.png and b/submodules/PremiumUI/Resources/thumbsup.png differ diff --git a/submodules/PremiumUI/Sources/PremiumIntroScreen.swift b/submodules/PremiumUI/Sources/PremiumIntroScreen.swift index bc12fbda15..331197b4d8 100644 --- a/submodules/PremiumUI/Sources/PremiumIntroScreen.swift +++ b/submodules/PremiumUI/Sources/PremiumIntroScreen.swift @@ -1839,12 +1839,12 @@ private final class PremiumIntroScreenComponent: CombinedComponent { if let topContentOffset = state.topContentOffset, topContentOffset >= 123.0 { starIsVisible = false } - + var isIntro = true if case .profile = context.component.source { isIntro = false } - + let star = star.update( component: PremiumStarComponent(isIntro: isIntro, isVisible: starIsVisible, hasIdleAnimations: state.hasIdleAnimations), availableSize: CGSize(width: min(390.0, context.availableSize.width), height: 220.0), diff --git a/submodules/PremiumUI/Sources/PremiumStarComponent.swift b/submodules/PremiumUI/Sources/PremiumStarComponent.swift index 92bf12d1e2..f2948a401c 100644 --- a/submodules/PremiumUI/Sources/PremiumStarComponent.swift +++ b/submodules/PremiumUI/Sources/PremiumStarComponent.swift @@ -19,7 +19,7 @@ private func rad2deg(_ number: Float) -> Float { } private func generateParticlesTexture() -> UIImage { - return UIImage() + return UIImage() } private func generateFlecksTexture() -> UIImage { diff --git a/submodules/TelegramCore/Sources/Authorization.swift b/submodules/TelegramCore/Sources/Authorization.swift index 2cd0cea713..0f27e8431a 100644 --- a/submodules/TelegramCore/Sources/Authorization.swift +++ b/submodules/TelegramCore/Sources/Authorization.swift @@ -364,7 +364,7 @@ public func sendLoginEmailCode(account: UnauthorizedAccount, email: String) -> S |> ignoreValues } -public func verifyLoginEmail(account: UnauthorizedAccount, code: AuthorizationCode.EmailVerification) -> Signal { +public func verifyLoginEmailSetup(account: UnauthorizedAccount, code: AuthorizationCode.EmailVerification) -> Signal { return account.postbox.transaction { transaction -> Signal in if let state = transaction.getState() as? UnauthorizedAccountState { switch state.contents { diff --git a/submodules/TelegramUI/Sources/AuthorizationSequenceCodeEntryController.swift b/submodules/TelegramUI/Sources/AuthorizationSequenceCodeEntryController.swift index 25816d8d00..dec21fe7c4 100644 --- a/submodules/TelegramUI/Sources/AuthorizationSequenceCodeEntryController.swift +++ b/submodules/TelegramUI/Sources/AuthorizationSequenceCodeEntryController.swift @@ -16,6 +16,8 @@ final class AuthorizationSequenceCodeEntryController: ViewController { private let openUrl: (String) -> Void var loginWithCode: ((String) -> Void)? + var signInWithApple: (() -> Void)? + var reset: (() -> Void)? var requestNextOption: (() -> Void)? @@ -24,6 +26,8 @@ final class AuthorizationSequenceCodeEntryController: ViewController { private let hapticFeedback = HapticFeedback() + private var appleSignInAllowed = false + var inProgress: Bool = false { didSet { if self.inProgress { @@ -76,6 +80,10 @@ final class AuthorizationSequenceCodeEntryController: ViewController { self?.continueWithCode(code) } + self.controllerNode.signInWithApple = { [weak self] in + self?.signInWithApple?() + } + self.controllerNode.requestNextOption = { [weak self] in self?.requestNextOption?() } @@ -89,7 +97,11 @@ final class AuthorizationSequenceCodeEntryController: ViewController { } if let (number, codeType, nextType, timeout) = self.data { - self.controllerNode.updateData(number: number, codeType: codeType, nextType: nextType, timeout: timeout) + var appleSignInAllowed = false + if case let .email(_, _, _, appleSignInAllowedValue, _) = codeType { + appleSignInAllowed = appleSignInAllowedValue + } + self.controllerNode.updateData(number: number, codeType: codeType, nextType: nextType, timeout: timeout, appleSignInAllowed: appleSignInAllowed) } } @@ -113,8 +125,14 @@ final class AuthorizationSequenceCodeEntryController: ViewController { self.title = nil } self.data = (number, codeType, nextType, timeout) + + var appleSignInAllowed = false + if case let .email(_, _, _, appleSignInAllowedValue, _) = codeType { + appleSignInAllowed = appleSignInAllowedValue + } + if self.isNodeLoaded { - self.controllerNode.updateData(number: number, codeType: codeType, nextType: nextType, timeout: timeout) + self.controllerNode.updateData(number: number, codeType: codeType, nextType: nextType, timeout: timeout, appleSignInAllowed: appleSignInAllowed) self.requestLayout(transition: .immediate) } } diff --git a/submodules/TelegramUI/Sources/AuthorizationSequenceCodeEntryControllerNode.swift b/submodules/TelegramUI/Sources/AuthorizationSequenceCodeEntryControllerNode.swift index ce6428dd03..d40436a39f 100644 --- a/submodules/TelegramUI/Sources/AuthorizationSequenceCodeEntryControllerNode.swift +++ b/submodules/TelegramUI/Sources/AuthorizationSequenceCodeEntryControllerNode.swift @@ -7,6 +7,7 @@ import SwiftSignalKit import TelegramPresentationData import TextFormat import AuthorizationUI +import AuthenticationServices import CodeInputView import PhoneNumberFormat import AnimatedStickerNode @@ -25,6 +26,9 @@ final class AuthorizationSequenceCodeEntryControllerNode: ASDisplayNode, UITextF private let nextOptionTitleNode: ImmediateTextNode private let nextOptionButtonNode: HighlightableButtonNode + private let dividerNode: AuthorizationDividerNode + private var signInWithAppleButton: UIControl? + private let codeInputView: CodeInputView private var codeType: SentAuthorizationCodeType? @@ -34,6 +38,8 @@ final class AuthorizationSequenceCodeEntryControllerNode: ASDisplayNode, UITextF private var layoutArguments: (ContainerViewLayout, CGFloat)? + private var appleSignInAllowed = false + var phoneNumber: String = "" { didSet { if self.phoneNumber != oldValue { @@ -49,6 +55,8 @@ final class AuthorizationSequenceCodeEntryControllerNode: ASDisplayNode, UITextF } var loginWithCode: ((String) -> Void)? + var signInWithApple: (() -> Void)? + var requestNextOption: (() -> Void)? var requestAnotherOption: (() -> Void)? var updateNextEnabled: ((Bool) -> Void)? @@ -106,6 +114,13 @@ final class AuthorizationSequenceCodeEntryControllerNode: ASDisplayNode, UITextF self.codeInputView.textField.keyboardType = .numberPad } + self.dividerNode = AuthorizationDividerNode(theme: self.theme, strings: self.strings) + + if #available(iOS 13.0, *) { + self.signInWithAppleButton = ASAuthorizationAppleIDButton(authorizationButtonType: .signIn, authorizationButtonStyle: theme.overallDarkAppearance ? .white : .black) + (self.signInWithAppleButton as? ASAuthorizationAppleIDButton)?.cornerRadius = 11 + } + /*self.codeField = TextFieldNode() self.codeField.textField.font = Font.regular(24.0) self.codeField.textField.textAlignment = .center @@ -140,6 +155,7 @@ final class AuthorizationSequenceCodeEntryControllerNode: ASDisplayNode, UITextF self.addSubnode(self.currentOptionInfoNode) self.addSubnode(self.nextOptionButtonNode) self.addSubnode(self.animationNode) + self.addSubnode(self.dividerNode) self.codeInputView.updated = { [weak self] in guard let strongSelf = self else { @@ -154,12 +170,21 @@ final class AuthorizationSequenceCodeEntryControllerNode: ASDisplayNode, UITextF //self.codeField.textField.attributedPlaceholder = NSAttributedString(string: strings.Login_Code, font: Font.regular(24.0), textColor: self.theme.list.itemPlaceholderTextColor) self.nextOptionButtonNode.addTarget(self, action: #selector(self.nextOptionNodePressed), forControlEvents: .touchUpInside) + self.signInWithAppleButton?.addTarget(self, action: #selector(self.signInWithApplePressed), for: .touchUpInside) } deinit { self.countdownDisposable.dispose() } + override func didLoad() { + super.didLoad() + + if let signInWithAppleButton = self.signInWithAppleButton { + self.view.addSubview(signInWithAppleButton) + } + } + func updateCode(_ code: String) { self.codeInputView.text = code self.textChanged(text: code) @@ -189,10 +214,17 @@ final class AuthorizationSequenceCodeEntryControllerNode: ASDisplayNode, UITextF self.codeInputView.text = "" } - func updateData(number: String, codeType: SentAuthorizationCodeType, nextType: AuthorizationCodeNextType?, timeout: Int32?) { + func updateData(number: String, codeType: SentAuthorizationCodeType, nextType: AuthorizationCodeNextType?, timeout: Int32?, appleSignInAllowed: Bool) { self.codeType = codeType self.phoneNumber = number + var appleSignInAllowed = appleSignInAllowed + if #available(iOS 13.0, *) { + } else { + appleSignInAllowed = false + } + self.appleSignInAllowed = appleSignInAllowed + self.currentOptionNode.attributedText = authorizationCurrentOptionText(codeType, strings: self.strings, primaryColor: self.theme.list.itemPrimaryTextColor, accentColor: self.theme.list.itemAccentColor) if case .missedCall = codeType { self.currentOptionInfoNode.attributedText = NSAttributedString(string: self.strings.Login_CodePhonePatternInfoText, font: Font.regular(16.0), textColor: self.theme.list.itemPrimaryTextColor, paragraphAlignment: .center) @@ -394,8 +426,22 @@ final class AuthorizationSequenceCodeEntryControllerNode: ASDisplayNode, UITextF items.append(AuthorizationLayoutItem(node: self.codeInputView, size: codeFieldSize, spacingBefore: AuthorizationLayoutItemSpacing(weight: 40.0, maxValue: 100.0), spacingAfter: AuthorizationLayoutItemSpacing(weight: 0.0, maxValue: 0.0))) /*items.append(AuthorizationLayoutItem(node: self.codeField, size: CGSize(width: layout.size.width - 88.0, height: 44.0), spacingBefore: AuthorizationLayoutItemSpacing(weight: 40.0, maxValue: 100.0), spacingAfter: AuthorizationLayoutItemSpacing(weight: 0.0, maxValue: 0.0))) items.append(AuthorizationLayoutItem(node: self.codeSeparatorNode, size: CGSize(width: layout.size.width - 88.0, height: UIScreenPixel), spacingBefore: AuthorizationLayoutItemSpacing(weight: 0.0, maxValue: 0.0), spacingAfter: AuthorizationLayoutItemSpacing(weight: 0.0, maxValue: 0.0)))*/ - - items.append(AuthorizationLayoutItem(node: self.nextOptionButtonNode, size: nextOptionSize, spacingBefore: AuthorizationLayoutItemSpacing(weight: 50.0, maxValue: 120.0), spacingAfter: AuthorizationLayoutItemSpacing(weight: 0.0, maxValue: 0.0))) + + if self.appleSignInAllowed, let signInWithAppleButton = self.signInWithAppleButton { + self.nextOptionButtonNode.isHidden = true + signInWithAppleButton.isHidden = false + + let dividerSize = self.dividerNode.updateLayout(width: layout.size.width) + items.append(AuthorizationLayoutItem(node: self.dividerNode, size: dividerSize, spacingBefore: AuthorizationLayoutItemSpacing(weight: 50.0, maxValue: 120.0), spacingAfter: AuthorizationLayoutItemSpacing(weight: 0.0, maxValue: 0.0))) + + let buttonSize = CGSize(width: layout.size.width - 48.0, height: 50.0) + items.append(AuthorizationLayoutItem(view: signInWithAppleButton, size: buttonSize, spacingBefore: AuthorizationLayoutItemSpacing(weight: 10.0, maxValue: 10.0), spacingAfter: AuthorizationLayoutItemSpacing(weight: 0.0, maxValue: 0.0))) + } else { + self.signInWithAppleButton?.isHidden = true + self.dividerNode.isHidden = true + self.nextOptionButtonNode.isHidden = false + items.append(AuthorizationLayoutItem(node: self.nextOptionButtonNode, size: nextOptionSize, spacingBefore: AuthorizationLayoutItemSpacing(weight: 50.0, maxValue: 120.0), spacingAfter: AuthorizationLayoutItemSpacing(weight: 0.0, maxValue: 0.0))) + } } } else { self.titleIconNode.isHidden = true @@ -476,4 +522,8 @@ final class AuthorizationSequenceCodeEntryControllerNode: ASDisplayNode, UITextF @objc func nextOptionNodePressed() { self.requestAnotherOption?() } + + @objc func signInWithApplePressed() { + self.signInWithApple?() + } } diff --git a/submodules/TelegramUI/Sources/AuthorizationSequenceController.swift b/submodules/TelegramUI/Sources/AuthorizationSequenceController.swift index 445f213585..78b1df7c26 100644 --- a/submodules/TelegramUI/Sources/AuthorizationSequenceController.swift +++ b/submodules/TelegramUI/Sources/AuthorizationSequenceController.swift @@ -294,7 +294,7 @@ public final class AuthorizationSequenceController: NavigationController, MFMail } if case let .email(_, _, _, _, setup) = type, setup, case let .emailVerification(emailCode) = authorizationCode { - strongSelf.actionDisposable.set(((verifyLoginEmail(account: strongSelf.account, code: emailCode)) + strongSelf.actionDisposable.set(((verifyLoginEmailSetup(account: strongSelf.account, code: emailCode)) |> deliverOnMainQueue).start(error: { error in Queue.mainQueue().async { if let strongSelf = self, let controller = controller { @@ -475,10 +475,28 @@ public final class AuthorizationSequenceController: NavigationController, MFMail let _ = TelegramEngineUnauthorized(account: strongSelf.account).auth.setState(state: UnauthorizedAccountState(isTestingEnvironment: account.testingEnvironment, masterDatacenterId: account.masterDatacenterId, contents: .empty)).start() } } + controller.signInWithApple = { [weak self] in + guard let strongSelf = self else { + return + } + + strongSelf.signInWithAppleSetup = false + + if #available(iOS 13.0, *) { + let appleIdProvider = ASAuthorizationAppleIDProvider() + let request = appleIdProvider.createRequest() + + let authorizationController = ASAuthorizationController(authorizationRequests: [request]) + authorizationController.delegate = strongSelf + authorizationController.presentationContextProvider = strongSelf + authorizationController.performRequests() + } + } controller.updateData(number: formatPhoneNumber(number), codeType: type, nextType: nextType, timeout: timeout, termsOfService: termsOfService) return controller } + private var signInWithAppleSetup = false private func emailSetupController(appleSignInAllowed: Bool) -> AuthorizationSequenceEmailEntryController { var currentController: AuthorizationSequenceEmailEntryController? for c in self.viewControllers { @@ -533,6 +551,8 @@ public final class AuthorizationSequenceController: NavigationController, MFMail return } + strongSelf.signInWithAppleSetup = true + if #available(iOS 13.0, *) { let appleIdProvider = ASAuthorizationAppleIDProvider() let request = appleIdProvider.createRequest() @@ -559,8 +579,9 @@ public final class AuthorizationSequenceController: NavigationController, MFMail return } - self.actionDisposable.set((verifyLoginEmail(account: self.account, code: .appleToken(token)) - |> deliverOnMainQueue).start(error: { [weak self] error in + if self.signInWithAppleSetup { + self.actionDisposable.set((verifyLoginEmailSetup(account: self.account, code: .appleToken(token)) + |> deliverOnMainQueue).start(error: { [weak self, weak lastController] error in if let strongSelf = self, let lastController = lastController { let text: String switch error { @@ -576,6 +597,49 @@ public final class AuthorizationSequenceController: NavigationController, MFMail lastController.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: strongSelf.presentationData), title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), in: .window(.root)) } })) + } else { + self.actionDisposable.set( + authorizeWithCode(accountManager: self.sharedContext.accountManager, account: self.account, code: .emailVerification(.appleToken(token)), termsOfService: nil, forcedPasswordSetupNotice: { value in + guard let entry = CodableEntry(ApplicationSpecificCounterNotice(value: value)) else { + return nil + } + return (ApplicationSpecificNotice.forcedPasswordSetupKey(), entry) + }).start(next: { [weak self] result in + guard let strongSelf = self else { + return + } +// lastController?.inProgress = false + switch result { + case let .signUp(data): + let _ = beginSignUp(account: strongSelf.account, data: data).start() + case .loggedIn: + break + } + }, error: { [weak self, weak lastController] error in + Queue.mainQueue().async { + if let strongSelf = self, let lastController = lastController { +// controller.inProgress = false + + let text: String + switch error { + case .limitExceeded: + text = strongSelf.presentationData.strings.Login_CodeFloodError + case .invalidCode: + text = strongSelf.presentationData.strings.Login_InvalidCodeError + case .generic: + text = strongSelf.presentationData.strings.Login_UnknownError + case .codeExpired: + text = strongSelf.presentationData.strings.Login_CodeExpired + let account = strongSelf.account + let _ = TelegramEngineUnauthorized(account: strongSelf.account).auth.setState(state: UnauthorizedAccountState(isTestingEnvironment: account.testingEnvironment, masterDatacenterId: account.masterDatacenterId, contents: .empty)).start() + } + + lastController.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: strongSelf.presentationData), title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), in: .window(.root)) + } + } + }) + ) + } default: break } diff --git a/submodules/TelegramUI/Sources/AuthorizationSequenceEmailEntryControllerNode.swift b/submodules/TelegramUI/Sources/AuthorizationSequenceEmailEntryControllerNode.swift index 7c51a5e948..7a9a1bd7e7 100644 --- a/submodules/TelegramUI/Sources/AuthorizationSequenceEmailEntryControllerNode.swift +++ b/submodules/TelegramUI/Sources/AuthorizationSequenceEmailEntryControllerNode.swift @@ -9,6 +9,44 @@ import AnimatedStickerNode import TelegramAnimatedStickerNode import SolidRoundedButtonNode +final class AuthorizationDividerNode: ASDisplayNode { + private let titleNode: ImmediateTextNode + private let leftLineNode: ASDisplayNode + private let rightLineNode: ASDisplayNode + + init(theme: PresentationTheme, strings: PresentationStrings) { + self.titleNode = ImmediateTextNode() + self.titleNode.maximumNumberOfLines = 1 + self.titleNode.attributedText = NSAttributedString(string: "or", font: Font.regular(17.0), textColor: theme.list.itemSecondaryTextColor) + + self.leftLineNode = ASDisplayNode() + self.leftLineNode.backgroundColor = theme.list.itemSecondaryTextColor + + self.rightLineNode = ASDisplayNode() + self.rightLineNode.backgroundColor = theme.list.itemSecondaryTextColor + + super.init() + + self.addSubnode(self.titleNode) + self.addSubnode(self.leftLineNode) + self.addSubnode(self.rightLineNode) + } + + func updateLayout(width: CGFloat) -> CGSize { + let lineSize = CGSize(width: 33.0, height: UIScreenPixel) + let spacing: CGFloat = 7.0 + + let titleSize = self.titleNode.updateLayout(CGSize(width: width - (lineSize.width + spacing) * 2.0, height: .greatestFiniteMagnitude)) + + let height: CGFloat = 40.0 + let titleFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((width - lineSize.width) / 2.0), y: floor((height - titleSize.height) / 2.0)), size: titleSize) + self.titleNode.frame = titleFrame + self.leftLineNode.frame = CGRect(origin: CGPoint(x: titleFrame.minX - spacing - lineSize.width, y: floorToScreenPixels(height / 2.0)), size: lineSize) + self.rightLineNode.frame = CGRect(origin: CGPoint(x: titleFrame.maxX + spacing, y: floorToScreenPixels(height / 2.0)), size: lineSize) + return CGSize(width: width, height: height) + } +} + final class AuthorizationSequenceEmailEntryControllerNode: ASDisplayNode, UITextFieldDelegate { private let strings: PresentationStrings private let theme: PresentationTheme @@ -17,6 +55,7 @@ final class AuthorizationSequenceEmailEntryControllerNode: ASDisplayNode, UIText private let titleNode: ASTextNode private let noticeNode: ASTextNode + private let dividerNode: AuthorizationDividerNode private var signInWithAppleButton: UIControl? private let proceedNode: SolidRoundedButtonNode @@ -82,6 +121,8 @@ final class AuthorizationSequenceEmailEntryControllerNode: ASDisplayNode, UIText self.codeField.textField.tintColor = self.theme.list.itemAccentColor self.codeField.textField.placeholder = "Enter Your Email" + self.dividerNode = AuthorizationDividerNode(theme: self.theme, strings: self.strings) + super.init() self.setViewBlock({ @@ -98,6 +139,7 @@ final class AuthorizationSequenceEmailEntryControllerNode: ASDisplayNode, UIText self.addSubnode(self.proceedNode) self.addSubnode(self.noticeNode) self.addSubnode(self.animationNode) + self.addSubnode(self.dividerNode) self.codeField.textField.addTarget(self, action: #selector(self.textDidChange), for: .editingChanged) self.proceedNode.pressed = { [weak self] in @@ -169,17 +211,23 @@ final class AuthorizationSequenceEmailEntryControllerNode: ASDisplayNode, UIText items.append(AuthorizationLayoutItem(node: self.codeField, size: CGSize(width: layout.size.width - 88.0, height: 44.0), spacingBefore: AuthorizationLayoutItemSpacing(weight: 32.0, maxValue: 60.0), spacingAfter: AuthorizationLayoutItemSpacing(weight: 0.0, maxValue: 0.0))) items.append(AuthorizationLayoutItem(node: self.codeSeparatorNode, size: CGSize(width: layout.size.width - 48.0, height: UIScreenPixel), spacingBefore: AuthorizationLayoutItemSpacing(weight: 0.0, maxValue: 0.0), spacingAfter: AuthorizationLayoutItemSpacing(weight: 0.0, maxValue: 0.0))) - items.append(AuthorizationLayoutItem(node: self.proceedNode, size: proceedSize, spacingBefore: AuthorizationLayoutItemSpacing(weight: 48.0, maxValue: 100.0), spacingAfter: AuthorizationLayoutItemSpacing(weight: 0.0, maxValue: 0.0))) + if let _ = self.signInWithAppleButton, self.appleSignInAllowed { + self.dividerNode.isHidden = false + let dividerSize = self.dividerNode.updateLayout(width: layout.size.width) + items.append(AuthorizationLayoutItem(node: self.dividerNode, size: dividerSize, spacingBefore: AuthorizationLayoutItemSpacing(weight: 48.0, maxValue: 100.0), spacingAfter: AuthorizationLayoutItemSpacing(weight: 0.0, maxValue: 0.0))) + } else { + self.dividerNode.isHidden = true + } + + items.append(AuthorizationLayoutItem(node: self.proceedNode, size: proceedSize, spacingBefore: self.dividerNode.isHidden ? AuthorizationLayoutItemSpacing(weight: 48.0, maxValue: 100.0) : AuthorizationLayoutItemSpacing(weight: 10.0, maxValue: 10.0), spacingAfter: AuthorizationLayoutItemSpacing(weight: 0.0, maxValue: 0.0))) let _ = layoutAuthorizationItems(bounds: CGRect(origin: CGPoint(x: 0.0, y: insets.top), size: CGSize(width: layout.size.width, height: layout.size.height - insets.top - insets.bottom - 20.0)), items: items, transition: transition, failIfDoesNotFit: false) - if let signInWithAppleButton = self.signInWithAppleButton { - if self.appleSignInAllowed { - signInWithAppleButton.isHidden = false - transition.updateFrame(view: signInWithAppleButton, frame: self.proceedNode.frame) - } else { - signInWithAppleButton.isHidden = true - } + if let signInWithAppleButton = self.signInWithAppleButton, self.appleSignInAllowed { + signInWithAppleButton.isHidden = false + transition.updateFrame(view: signInWithAppleButton, frame: self.proceedNode.frame) + } else { + self.signInWithAppleButton?.isHidden = true } } diff --git a/submodules/TelegramUI/Sources/AuthorizationSequencePhoneEntryControllerNode.swift b/submodules/TelegramUI/Sources/AuthorizationSequencePhoneEntryControllerNode.swift index a5595b0645..e814836f2f 100644 --- a/submodules/TelegramUI/Sources/AuthorizationSequencePhoneEntryControllerNode.swift +++ b/submodules/TelegramUI/Sources/AuthorizationSequencePhoneEntryControllerNode.swift @@ -235,8 +235,6 @@ private final class ContactSyncNode: ASDisplayNode { } } - - final class AuthorizationSequencePhoneEntryControllerNode: ASDisplayNode { private let sharedContext: SharedAccountContext private var account: UnauthorizedAccount diff --git a/submodules/TelegramUI/Sources/AuthorizationSequenceSignUpController.swift b/submodules/TelegramUI/Sources/AuthorizationSequenceSignUpController.swift index 767d4c30f4..c393e46155 100644 --- a/submodules/TelegramUI/Sources/AuthorizationSequenceSignUpController.swift +++ b/submodules/TelegramUI/Sources/AuthorizationSequenceSignUpController.swift @@ -50,7 +50,7 @@ final class AuthorizationSequenceSignUpController: ViewController { self.statusBar.statusBarStyle = presentationData.theme.intro.statusBarStyle.style - self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Next, style: .done, target: self, action: #selector(self.nextPressed)) +// self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Next, style: .done, target: self, action: #selector(self.nextPressed)) self.attemptNavigation = { _ in return false diff --git a/submodules/TelegramUI/Sources/AuthorizationSequenceSignUpControllerNode.swift b/submodules/TelegramUI/Sources/AuthorizationSequenceSignUpControllerNode.swift index 1655c94837..c7b212866f 100644 --- a/submodules/TelegramUI/Sources/AuthorizationSequenceSignUpControllerNode.swift +++ b/submodules/TelegramUI/Sources/AuthorizationSequenceSignUpControllerNode.swift @@ -5,6 +5,8 @@ import Display import TelegramPresentationData import TextFormat import Markdown +import AuthorizationUI +import SolidRoundedButtonNode private func roundCorners(diameter: CGFloat) -> UIImage { UIGraphicsBeginImageContextWithOptions(CGSize(width: diameter, height: diameter), false, 0.0) @@ -34,6 +36,7 @@ final class AuthorizationSequenceSignUpControllerNode: ASDisplayNode, UITextFiel private let lastSeparatorNode: ASDisplayNode private let currentPhotoNode: ASImageNode private let addPhotoButton: HighlightableButtonNode + private let proceedNode: SolidRoundedButtonNode private var layoutArguments: (ContainerViewLayout, CGFloat)? @@ -75,20 +78,20 @@ final class AuthorizationSequenceSignUpControllerNode: ASDisplayNode, UITextFiel self.titleNode = ASTextNode() self.titleNode.isUserInteractionEnabled = false self.titleNode.displaysAsynchronously = false - self.titleNode.attributedText = NSAttributedString(string: self.strings.Login_InfoTitle, font: Font.light(30.0), textColor: theme.list.itemPrimaryTextColor) + self.titleNode.attributedText = NSAttributedString(string: self.strings.Login_InfoTitle, font: Font.semibold(28.0), textColor: theme.list.itemPrimaryTextColor) self.currentOptionNode = ASTextNode() self.currentOptionNode.isUserInteractionEnabled = false self.currentOptionNode.displaysAsynchronously = false - self.currentOptionNode.attributedText = NSAttributedString(string: self.strings.Login_InfoHelp, font: Font.regular(16.0), textColor: theme.list.itemPlaceholderTextColor, paragraphAlignment: .center) + self.currentOptionNode.attributedText = NSAttributedString(string: self.strings.Login_InfoHelp, font: Font.regular(16.0), textColor: theme.list.itemPrimaryTextColor, paragraphAlignment: .center) self.termsNode = ImmediateTextNode() self.termsNode.textAlignment = .center self.termsNode.maximumNumberOfLines = 0 self.termsNode.displaysAsynchronously = false - let body = MarkdownAttributeSet(font: Font.regular(16.0), textColor: theme.list.itemPrimaryTextColor) - let link = MarkdownAttributeSet(font: Font.regular(16.0), textColor: theme.list.itemAccentColor, additionalAttributes: [TelegramTextAttributes.URL: ""]) - self.termsNode.attributedText = parseMarkdownIntoAttributedString(strings.Login_TermsOfServiceLabel.replacingOccurrences(of: "]", with: "]()"), attributes: MarkdownAttributes(body: body, bold: body, link: link, linkAttribute: { _ in nil }), textAlignment: .center) + let body = MarkdownAttributeSet(font: Font.regular(13.0), textColor: theme.list.itemSecondaryTextColor) + let link = MarkdownAttributeSet(font: Font.regular(13.0), textColor: theme.list.itemAccentColor, additionalAttributes: [TelegramTextAttributes.URL: ""]) + self.termsNode.attributedText = parseMarkdownIntoAttributedString(strings.Login_TermsOfServiceLabel.replacingOccurrences(of: "\n", with: " ").replacingOccurrences(of: "]", with: "]()"), attributes: MarkdownAttributes(body: body, bold: body, link: link, linkAttribute: { _ in nil }), textAlignment: .center) self.firstSeparatorNode = ASDisplayNode() self.firstSeparatorNode.isLayerBacked = true @@ -132,12 +135,14 @@ final class AuthorizationSequenceSignUpControllerNode: ASDisplayNode, UITextFiel self.currentPhotoNode.displayWithoutProcessing = true self.addPhotoButton = HighlightableButtonNode() - self.addPhotoButton.setImage(generateTintedImage(image: UIImage(bundleImageName: "Avatar/EditAvatarIconLarge"), color: self.theme.list.itemPlaceholderTextColor), for: .normal) - self.addPhotoButton.setBackgroundImage(generateCircleImage(diameter: 110.0, lineWidth: 1.0, color: self.theme.list.itemPlaceholderTextColor), for: .normal) - + self.addPhotoButton.setImage(generateTintedImage(image: UIImage(bundleImageName: "Avatar/EditAvatarIconLarge"), color: self.theme.list.itemAccentColor), for: .normal) + self.addPhotoButton.setBackgroundImage(generateFilledCircleImage(diameter: 110.0, color: self.theme.list.itemAccentColor.withAlphaComponent(0.1), strokeColor: nil, strokeWidth: nil, backgroundColor: nil), for: .normal) + self.addPhotoButton.addSubnode(self.currentPhotoNode) self.addPhotoButton.allowsGroupOpacity = true + self.proceedNode = SolidRoundedButtonNode(title: "Continue", theme: SolidRoundedButtonTheme(theme: self.theme), height: 50.0, cornerRadius: 11.0, gloss: false) + super.init() self.setViewBlock({ @@ -158,6 +163,7 @@ final class AuthorizationSequenceSignUpControllerNode: ASDisplayNode, UITextFiel self.addSubnode(self.termsNode) self.termsNode.isHidden = true self.addSubnode(self.addPhotoButton) + self.addSubnode(self.proceedNode) self.addPhotoButton.addTarget(self, action: #selector(self.addPhotoPressed), forControlEvents: .touchUpInside) @@ -174,6 +180,13 @@ final class AuthorizationSequenceSignUpControllerNode: ASDisplayNode, UITextFiel self?.openTermsOfService?() } } + + self.proceedNode.pressed = { [weak self] in + if let strongSelf = self { + let name = strongSelf.currentName + strongSelf.signUpWithName?(name.0, name.1) + } + } } func updateData(firstName: String, lastName: String, hasTermsOfService: Bool) { @@ -193,91 +206,110 @@ final class AuthorizationSequenceSignUpControllerNode: ASDisplayNode, UITextFiel if let inputHeight = layout.inputHeight { insets.bottom += max(inputHeight, layout.standardInputHeight) } - - let availableHeight = max(1.0, layout.size.height - insets.top - insets.bottom) - - if max(layout.size.width, layout.size.height) > 1023.0 { - self.titleNode.attributedText = NSAttributedString(string: self.strings.Login_InfoTitle, font: Font.light(40.0), textColor: self.theme.list.itemPrimaryTextColor) - } else { - self.titleNode.attributedText = NSAttributedString(string: self.strings.Login_InfoTitle, font: Font.light(30.0), textColor: self.theme.list.itemPrimaryTextColor) - } - + + self.titleNode.attributedText = NSAttributedString(string: self.strings.Login_InfoTitle, font: Font.semibold(28.0), textColor: self.theme.list.itemPrimaryTextColor) let titleSize = self.titleNode.measure(CGSize(width: layout.size.width, height: CGFloat.greatestFiniteMagnitude)) - let additionalTitleSpacing: CGFloat - if titleSize.width > layout.size.width - 160.0 { - additionalTitleSpacing = 44.0 - } else { - additionalTitleSpacing = 0.0 - } - let minimalTitleSpacing: CGFloat = 10.0 - let maxTitleSpacing: CGFloat = 22.0 - let fieldHeight: CGFloat = 57.0 - let inputFieldsHeight: CGFloat = fieldHeight * 2.0 - let leftInset: CGFloat = 130.0 +// let additionalTitleSpacing: CGFloat +// if titleSize.width > layout.size.width - 160.0 { +// additionalTitleSpacing = 44.0 +// } else { +// additionalTitleSpacing = 0.0 +// } - let minimalNoticeSpacing: CGFloat = 11.0 - let maxNoticeSpacing: CGFloat = 35.0 + let fieldHeight: CGFloat = 54.0 + + let sideInset: CGFloat = 24.0 + let innerInset: CGFloat = 16.0 + +// let minimalNoticeSpacing: CGFloat = 11.0 +// let maxNoticeSpacing: CGFloat = 35.0 let noticeSize = self.currentOptionNode.measure(CGSize(width: layout.size.width - 28.0, height: CGFloat.greatestFiniteMagnitude)) let termsSize = self.termsNode.updateLayout(CGSize(width: layout.size.width - 28.0, height: CGFloat.greatestFiniteMagnitude)) +// +// let noticeHeight: CGFloat = noticeSize.height + (self.termsNode.isHidden ? 0.0 : (termsSize.height + 4.0)) +// +// let minimalTermsOfServiceSpacing: CGFloat = 6.0 +// let maxTermsOfServiceSpacing: CGFloat = 20.0 +// let minTrailingSpacing: CGFloat = 10.0 +// +// let inputHeight = inputFieldsHeight +// let essentialHeight = additionalTitleSpacing + titleSize.height + minimalTitleSpacing + inputHeight + minimalNoticeSpacing + noticeHeight +// let additionalHeight = minimalTermsOfServiceSpacing + minTrailingSpacing +// +// let navigationHeight: CGFloat +// if essentialHeight + additionalHeight > availableHeight || availableHeight * 0.66 - inputHeight < additionalHeight { +// navigationHeight = min(floor(availableHeight * 0.3), availableHeight - inputFieldsHeight) +// } else { +// navigationHeight = floor(availableHeight * 0.3) +// } +// +// let titleOffset: CGFloat +// if navigationHeight * 0.5 < titleSize.height + minimalTitleSpacing { +// titleOffset = max(navigationBarHeight, floor((navigationHeight - titleSize.height) / 2.0)) +// } else { +// titleOffset = max(navigationBarHeight, max(navigationHeight * 0.5, navigationHeight - maxTitleSpacing - titleSize.height)) +// } +// transition.updateFrame(node: self.titleNode, frame: CGRect(origin: CGPoint(x: floorToScreenPixels((layout.size.width - titleSize.width) / 2.0), y: titleOffset), size: titleSize)) +// +// let avatarSize: CGSize = CGSize(width: 110.0, height: 110.0) +// let addPhotoButtonFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((layout.size.width - avatarSize.width) / 2.0), y: navigationHeight + 10.0), size: avatarSize) +// transition.updateFrame(node: self.addPhotoButton, frame: addPhotoButtonFrame) +// self.currentPhotoNode.frame = CGRect(origin: CGPoint(), size: addPhotoButtonFrame.size) +// +// +// +// let firstFieldFrame = CGRect(origin: CGPoint(x: sideInset + innerInset, y: navigationHeight + 3.0), size: CGSize(width: layout.size.width - (sideInset + innerInset) * 2.0, height: fieldHeight)) +// transition.updateFrame(node: self.firstNameField, frame: firstFieldFrame) +// +// let lastFieldFrame = CGRect(origin: CGPoint(x: firstFieldFrame.minX, y: firstFieldFrame.maxY), size: CGSize(width: firstFieldFrame.size.width, height: fieldHeight)) +// transition.updateFrame(node: self.lastNameField, frame: lastFieldFrame) +// +// transition.updateFrame(node: self.firstSeparatorNode, frame: CGRect(origin: CGPoint(x: sideInset, y: firstFieldFrame.maxY), size: CGSize(width: layout.size.width - sideInset * 2.0, height: UIScreenPixel))) +// transition.updateFrame(node: self.lastSeparatorNode, frame: CGRect(origin: CGPoint(x: sideInset, y: lastFieldFrame.maxY), size: CGSize(width: layout.size.width - sideInset * 2.0, height: UIScreenPixel))) +// +// let additionalAvailableHeight = max(1.0, availableHeight - lastFieldFrame.maxY) +// let additionalAvailableSpacing = max(1.0, additionalAvailableHeight - noticeHeight) +// let noticeSpacingFactor = maxNoticeSpacing / (maxNoticeSpacing + maxTermsOfServiceSpacing + minTrailingSpacing) +// let termsOfServiceSpacingFactor = maxTermsOfServiceSpacing / (maxNoticeSpacing + maxTermsOfServiceSpacing + minTrailingSpacing) +// +// let noticeSpacing: CGFloat +// let termsOfServiceSpacing: CGFloat +// if additionalAvailableHeight <= maxNoticeSpacing + noticeHeight + maxTermsOfServiceSpacing + minTrailingSpacing { +// termsOfServiceSpacing = min(floor(termsOfServiceSpacingFactor * additionalAvailableSpacing), maxTermsOfServiceSpacing) +// noticeSpacing = floor((additionalAvailableHeight - termsOfServiceSpacing - noticeHeight) / 2.0) +// } else { +// noticeSpacing = min(floor(noticeSpacingFactor * additionalAvailableSpacing), maxNoticeSpacing) +// termsOfServiceSpacing = min(floor(termsOfServiceSpacingFactor * additionalAvailableSpacing), maxTermsOfServiceSpacing) +// } +// +// let currentOptionFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - noticeSize.width) / 2.0), y: lastFieldFrame.maxY + max(0.0, noticeSpacing)), size: noticeSize) +// transition.updateFrame(node: self.currentOptionNode, frame: currentOptionFrame) +// let termsFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - termsSize.width) / 2.0), y: layout.size.height - insets.bottom - termsSize.height - 4.0), size: termsSize) +// transition.updateFrame(node: self.termsNode, frame: termsFrame) +// - let noticeHeight: CGFloat = noticeSize.height + (self.termsNode.isHidden ? 0.0 : (termsSize.height + 4.0)) + let avatarSize: CGSize = CGSize(width: 110.0, height: 110.0) + var items: [AuthorizationLayoutItem] = [] + items.append(AuthorizationLayoutItem(node: self.addPhotoButton, size: avatarSize, spacingBefore: AuthorizationLayoutItemSpacing(weight: 16.0, maxValue: 16.0), spacingAfter: AuthorizationLayoutItemSpacing(weight: 0.0, maxValue: 0.0))) + self.currentPhotoNode.frame = CGRect(origin: CGPoint(), size: avatarSize) - let minimalTermsOfServiceSpacing: CGFloat = 6.0 - let maxTermsOfServiceSpacing: CGFloat = 20.0 - let minTrailingSpacing: CGFloat = 10.0 + items.append(AuthorizationLayoutItem(node: self.titleNode, size: titleSize, spacingBefore: AuthorizationLayoutItemSpacing(weight: 18.0, maxValue: 18.0), spacingAfter: AuthorizationLayoutItemSpacing(weight: 0.0, maxValue: 0.0))) + items.append(AuthorizationLayoutItem(node: self.currentOptionNode, size: noticeSize, spacingBefore: AuthorizationLayoutItemSpacing(weight: 20.0, maxValue: 20.0), spacingAfter: AuthorizationLayoutItemSpacing(weight: 0.0, maxValue: 0.0))) - let inputHeight = inputFieldsHeight - let essentialHeight = additionalTitleSpacing + titleSize.height + minimalTitleSpacing + inputHeight + minimalNoticeSpacing + noticeHeight - let additionalHeight = minimalTermsOfServiceSpacing + minTrailingSpacing + items.append(AuthorizationLayoutItem(node: self.firstNameField, size: CGSize(width: layout.size.width - (sideInset + innerInset) * 2.0, height: fieldHeight), spacingBefore: AuthorizationLayoutItemSpacing(weight: 32.0, maxValue: 60.0), spacingAfter: AuthorizationLayoutItemSpacing(weight: 0.0, maxValue: 0.0))) + items.append(AuthorizationLayoutItem(node: self.firstSeparatorNode, size: CGSize(width: layout.size.width - sideInset * 2.0, height: UIScreenPixel), spacingBefore: AuthorizationLayoutItemSpacing(weight: 0.0, maxValue: 0.0), spacingAfter: AuthorizationLayoutItemSpacing(weight: 0.0, maxValue: 0.0))) - let navigationHeight: CGFloat - if essentialHeight + additionalHeight > availableHeight || availableHeight * 0.66 - inputHeight < additionalHeight { - navigationHeight = min(floor(availableHeight * 0.3), availableHeight - inputFieldsHeight) - } else { - navigationHeight = floor(availableHeight * 0.3) - } + items.append(AuthorizationLayoutItem(node: self.lastNameField, size: CGSize(width: layout.size.width - (sideInset + innerInset) * 2.0, height: fieldHeight), spacingBefore: AuthorizationLayoutItemSpacing(weight: 0.0, maxValue: 0.0), spacingAfter: AuthorizationLayoutItemSpacing(weight: 0.0, maxValue: 0.0))) + items.append(AuthorizationLayoutItem(node: self.lastSeparatorNode, size: CGSize(width: layout.size.width - sideInset * 2.0, height: UIScreenPixel), spacingBefore: AuthorizationLayoutItemSpacing(weight: 0.0, maxValue: 0.0), spacingAfter: AuthorizationLayoutItemSpacing(weight: 0.0, maxValue: 0.0))) - let titleOffset: CGFloat - if navigationHeight * 0.5 < titleSize.height + minimalTitleSpacing { - titleOffset = max(navigationBarHeight, floor((navigationHeight - titleSize.height) / 2.0)) - } else { - titleOffset = max(navigationBarHeight, max(navigationHeight * 0.5, navigationHeight - maxTitleSpacing - titleSize.height)) - } - transition.updateFrame(node: self.titleNode, frame: CGRect(origin: CGPoint(x: floor((layout.size.width - titleSize.width) / 2.0), y: titleOffset), size: titleSize)) + items.append(AuthorizationLayoutItem(node: self.termsNode, size: termsSize, spacingBefore: AuthorizationLayoutItemSpacing(weight: 48.0, maxValue: 100.0), spacingAfter: AuthorizationLayoutItemSpacing(weight: 0.0, maxValue: 0.0))) - let addPhotoButtonFrame = CGRect(origin: CGPoint(x: 10.0, y: navigationHeight + 10.0), size: CGSize(width: 110.0, height: 110.0)) - transition.updateFrame(node: self.addPhotoButton, frame: addPhotoButtonFrame) - self.currentPhotoNode.frame = CGRect(origin: CGPoint(), size: addPhotoButtonFrame.size) - - let firstFieldFrame = CGRect(origin: CGPoint(x: leftInset, y: navigationHeight + 3.0), size: CGSize(width: layout.size.width - leftInset, height: fieldHeight)) - transition.updateFrame(node: self.firstNameField, frame: firstFieldFrame) - - let lastFieldFrame = CGRect(origin: CGPoint(x: firstFieldFrame.minX, y: firstFieldFrame.maxY), size: CGSize(width: firstFieldFrame.size.width, height: fieldHeight)) - transition.updateFrame(node: self.lastNameField, frame: lastFieldFrame) - - transition.updateFrame(node: self.firstSeparatorNode, frame: CGRect(origin: CGPoint(x: leftInset, y: firstFieldFrame.maxY), size: CGSize(width: layout.size.width - leftInset, height: UIScreenPixel))) - transition.updateFrame(node: self.lastSeparatorNode, frame: CGRect(origin: CGPoint(x: leftInset, y: lastFieldFrame.maxY), size: CGSize(width: layout.size.width - leftInset, height: UIScreenPixel))) - - let additionalAvailableHeight = max(1.0, availableHeight - lastFieldFrame.maxY) - let additionalAvailableSpacing = max(1.0, additionalAvailableHeight - noticeHeight) - let noticeSpacingFactor = maxNoticeSpacing / (maxNoticeSpacing + maxTermsOfServiceSpacing + minTrailingSpacing) - let termsOfServiceSpacingFactor = maxTermsOfServiceSpacing / (maxNoticeSpacing + maxTermsOfServiceSpacing + minTrailingSpacing) - - let noticeSpacing: CGFloat - let termsOfServiceSpacing: CGFloat - if additionalAvailableHeight <= maxNoticeSpacing + noticeHeight + maxTermsOfServiceSpacing + minTrailingSpacing { - termsOfServiceSpacing = min(floor(termsOfServiceSpacingFactor * additionalAvailableSpacing), maxTermsOfServiceSpacing) - noticeSpacing = floor((additionalAvailableHeight - termsOfServiceSpacing - noticeHeight) / 2.0) - } else { - noticeSpacing = min(floor(noticeSpacingFactor * additionalAvailableSpacing), maxNoticeSpacing) - termsOfServiceSpacing = min(floor(termsOfServiceSpacingFactor * additionalAvailableSpacing), maxTermsOfServiceSpacing) - } - - let currentOptionFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - noticeSize.width) / 2.0), y: lastFieldFrame.maxY + max(0.0, noticeSpacing)), size: noticeSize) - transition.updateFrame(node: self.currentOptionNode, frame: currentOptionFrame) - let termsFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - termsSize.width) / 2.0), y: layout.size.height - insets.bottom - termsSize.height - 4.0), size: termsSize) - transition.updateFrame(node: self.termsNode, frame: termsFrame) + let proceedHeight = self.proceedNode.updateLayout(width: layout.size.width - 48.0, transition: transition) + let proceedSize = CGSize(width: layout.size.width - 48.0, height: proceedHeight) + items.append(AuthorizationLayoutItem(node: self.proceedNode, size: proceedSize, spacingBefore: AuthorizationLayoutItemSpacing(weight: 20.0, maxValue: 20.0), spacingAfter: AuthorizationLayoutItemSpacing(weight: 0.0, maxValue: 0.0))) + + let _ = layoutAuthorizationItems(bounds: CGRect(origin: CGPoint(x: 0.0, y: insets.top), size: CGSize(width: layout.size.width, height: layout.size.height - insets.top - insets.bottom - 20.0)), items: items, transition: transition, failIfDoesNotFit: false) } func activateInput() { diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index 7c9d56f361..5575233382 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -9835,7 +9835,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G if let attachBotStart = self.attachBotStart { self.attachBotStart = nil - self.presentAttachmentBot(botId: attachBotStart.botId, payload: attachBotStart.payload) + self.presentAttachmentBot(botId: attachBotStart.botId, payload: attachBotStart.payload, justInstalled: attachBotStart.justInstalled) } } @@ -11235,12 +11235,12 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G }) } - public func presentAttachmentBot(botId: PeerId, payload: String?) { + public func presentAttachmentBot(botId: PeerId, payload: String?, justInstalled: Bool) { self.attachmentController?.dismiss(animated: true, completion: nil) - self.presentAttachmentMenu(editMediaOptions: nil, editMediaReference: nil, botId: botId, botPayload: payload) + self.presentAttachmentMenu(editMediaOptions: nil, editMediaReference: nil, botId: botId, botPayload: payload, botJustInstalled: justInstalled) } - private func presentAttachmentMenu(editMediaOptions: MessageMediaEditingOptions?, editMediaReference: AnyMediaReference?, botId: PeerId? = nil, botPayload: String? = nil) { + private func presentAttachmentMenu(editMediaOptions: MessageMediaEditingOptions?, editMediaReference: AnyMediaReference?, botId: PeerId? = nil, botPayload: String? = nil, botJustInstalled: Bool = false) { guard let peer = self.presentationInterfaceState.renderedPeer?.peer else { return } @@ -11285,33 +11285,35 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G isScheduledMessages = true } - let buttons: Signal<([AttachmentButtonType], AttachmentButtonType?), NoError> + var peerType: AttachMenuBots.Bot.PeerFlags = [] + if let user = peer as? TelegramUser { + if let _ = user.botInfo { + peerType.insert(.bot) + } else { + peerType.insert(.user) + } + } else if let _ = peer as? TelegramGroup { + peerType = .group + } else if let channel = peer as? TelegramChannel { + if case .broadcast = channel.info { + peerType = .channel + } else { + peerType = .group + } + } + + let buttons: Signal<([AttachmentButtonType], [AttachmentButtonType], AttachmentButtonType?), NoError> if !isScheduledMessages { buttons = self.context.engine.messages.attachMenuBots() |> map { attachMenuBots in var buttons = availableButtons + var allButtons = availableButtons + var initialButton: AttachmentButtonType? if botId == nil { initialButton = .gallery } - var peerType: AttachMenuBots.Bot.PeerFlags = [] - if let user = peer as? TelegramUser { - if let _ = user.botInfo { - peerType.insert(.bot) - } else { - peerType.insert(.user) - } - } else if let _ = peer as? TelegramGroup { - peerType = .group - } else if let channel = peer as? TelegramChannel { - if case .broadcast = channel.info { - peerType = .channel - } else { - peerType = .group - } - } - for bot in attachMenuBots.reversed() { var peerType = peerType if bot.peer.id == peer.id { @@ -11319,19 +11321,20 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G peerType.remove(.bot) } + let button: AttachmentButtonType = .app(bot.peer, bot.shortName, bot.icons) if !bot.peerTypes.intersection(peerType).isEmpty { - let button: AttachmentButtonType = .app(bot.peer, bot.shortName, bot.icons) buttons.insert(button, at: 1) if initialButton == nil && bot.peer.id == botId { initialButton = button } } + allButtons.insert(button, at: 1) } - return (buttons, initialButton) + return (buttons, allButtons, initialButton) } } else { - buttons = .single((availableButtons, .gallery)) + buttons = .single((availableButtons, availableButtons, .gallery)) } let dataSettings = self.context.sharedContext.accountManager.transaction { transaction -> GeneratedMediaStoreSettings in @@ -11344,25 +11347,35 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G return } - let (buttons, initialButton) = buttonsAndInitialButton + let (buttons, allButtons, initialButton) = buttonsAndInitialButton guard let initialButton = initialButton else { if let botId = botId { - let _ = (context.engine.messages.getAttachMenuBot(botId: botId) - |> deliverOnMainQueue).start(next: { bot in - let peer = EnginePeer(bot.peer) - let controller = addWebAppToAttachmentController(context: context, peerName: peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), icons: bot.icons, completion: { - let _ = (context.engine.messages.addBotToAttachMenu(botId: botId) - |> deliverOnMainQueue).start(error: { _ in - - }, completed: { - strongSelf.presentAttachmentBot(botId: botId, payload: botPayload) + if let button = allButtons.first(where: { button in + if case let .app(botPeer, _, _) = button, botPeer.id == botId { + return true + } else { + return false + } + }), case let .app(_, botName, _) = button { + strongSelf.present(UndoOverlayController(presentationData: presentationData, content: .info(title: nil, text: botJustInstalled ? strongSelf.presentationData.strings.WebApp_AddToAttachmentSucceeded(botName).string : strongSelf.presentationData.strings.WebApp_AddToAttachmentAlreadyAddedError), elevatedLayout: false, action: { _ in return false }), in: .current) + } else { + let _ = (context.engine.messages.getAttachMenuBot(botId: botId) + |> deliverOnMainQueue).start(next: { bot in + let peer = EnginePeer(bot.peer) + let controller = addWebAppToAttachmentController(context: context, peerName: peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), icons: bot.icons, completion: { + let _ = (context.engine.messages.addBotToAttachMenu(botId: botId) + |> deliverOnMainQueue).start(error: { _ in + + }, completed: { + strongSelf.presentAttachmentBot(botId: botId, payload: botPayload, justInstalled: true) + }) }) + strongSelf.present(controller, in: .window(.root)) + }, error: { _ in + strongSelf.present(textAlertController(context: context, updatedPresentationData: strongSelf.updatedPresentationData, title: nil, text: presentationData.strings.Login_UnknownError, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), in: .window(.root)) }) - strongSelf.present(controller, in: .window(.root)) - }, error: { _ in - strongSelf.present(textAlertController(context: context, updatedPresentationData: strongSelf.updatedPresentationData, title: nil, text: presentationData.strings.Login_UnknownError, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), in: .window(.root)) - }) + } } return } diff --git a/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift b/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift index 291fe52dab..0cf3016e65 100644 --- a/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift @@ -983,7 +983,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView { tmpWidth -= deliveryFailedInset let maximumContentWidth = floor(tmpWidth - layoutConstants.bubble.edgeInset - layoutConstants.bubble.edgeInset - layoutConstants.bubble.contentInsets.left - layoutConstants.bubble.contentInsets.right - avatarInset) - + let font = Font.regular(fontSizeForEmojiString(item.message.text)) let attributedText = stringWithAppliedEntities(item.message.text, entities: item.message.textEntitiesAttribute?.entities ?? [], baseColor: .black, linkColor: .black, baseFont: font, linkFont: font, boldFont: font, italicFont: font, boldItalicFont: font, fixedFont: font, blockQuoteFont: font, message: item.message) textLayoutAndApply = textLayout(TextNodeLayoutArguments(attributedString: attributedText, backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: maximumContentWidth, height: CGFloat.greatestFiniteMagnitude), alignment: .natural)) diff --git a/submodules/TelegramUI/Sources/NavigateToChatController.swift b/submodules/TelegramUI/Sources/NavigateToChatController.swift index 6fc9b3688e..40909b91ee 100644 --- a/submodules/TelegramUI/Sources/NavigateToChatController.swift +++ b/submodules/TelegramUI/Sources/NavigateToChatController.swift @@ -66,7 +66,7 @@ public func navigateToChatControllerImpl(_ params: NavigateToChatControllerParam }) } if let attachBotStart = params.attachBotStart { - controller.presentAttachmentBot(botId: attachBotStart.botId, payload: attachBotStart.payload) + controller.presentAttachmentBot(botId: attachBotStart.botId, payload: attachBotStart.payload, justInstalled: attachBotStart.justInstalled) } params.setupController(controller) found = true @@ -85,7 +85,7 @@ public func navigateToChatControllerImpl(_ params: NavigateToChatControllerParam }) } if let attachBotStart = params.attachBotStart { - controller.presentAttachmentBot(botId: attachBotStart.botId, payload: attachBotStart.payload) + controller.presentAttachmentBot(botId: attachBotStart.botId, payload: attachBotStart.payload, justInstalled: attachBotStart.justInstalled) } } else { controller = ChatControllerImpl(context: params.context, chatLocation: params.chatLocation, chatLocationContextHolder: params.chatLocationContextHolder, subject: params.subject, botStart: params.botStart, attachBotStart: params.attachBotStart, peekData: params.peekData, peerNearbyData: params.peerNearbyData, chatListFilter: params.chatListFilter, chatNavigationStack: params.chatNavigationStack) diff --git a/submodules/TelegramUI/Sources/OpenResolvedUrl.swift b/submodules/TelegramUI/Sources/OpenResolvedUrl.swift index aca743fddd..6c32e35454 100644 --- a/submodules/TelegramUI/Sources/OpenResolvedUrl.swift +++ b/submodules/TelegramUI/Sources/OpenResolvedUrl.swift @@ -579,13 +579,13 @@ func openResolvedUrlImpl(_ resolvedUrl: ResolvedUrl, context: AccountContext, ur if let navigationController = navigationController { let controller = context.sharedContext.makePeerSelectionController(PeerSelectionControllerParams(context: context, updatedPresentationData: updatedPresentationData, filter: filters, hasChatListSelector: true, hasContactSelector: false, title: presentationData.strings.WebApp_SelectChat)) controller.peerSelected = { peer in - let _ = context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(id: peer.id), attachBotStart: ChatControllerInitialAttachBotStart(botId: bot.peer.id, payload: payload), useExisting: true)) + let _ = context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(id: peer.id), attachBotStart: ChatControllerInitialAttachBotStart(botId: bot.peer.id, payload: payload, justInstalled: false), useExisting: true)) } navigationController.pushViewController(controller) } } else { if let navigationController = navigationController, case let .chat(chatPeerId, _) = urlContext { - let _ = context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(id: chatPeerId), attachBotStart: ChatControllerInitialAttachBotStart(botId: peerId, payload: payload), useExisting: true)) + let _ = context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(id: chatPeerId), attachBotStart: ChatControllerInitialAttachBotStart(botId: peerId, payload: payload, justInstalled: false), useExisting: true)) } else { presentError(presentationData.strings.WebApp_AddToAttachmentAlreadyAddedError) } @@ -622,13 +622,13 @@ func openResolvedUrlImpl(_ resolvedUrl: ResolvedUrl, context: AccountContext, ur if let navigationController = navigationController { let controller = context.sharedContext.makePeerSelectionController(PeerSelectionControllerParams(context: context, updatedPresentationData: updatedPresentationData, filter: filters, hasChatListSelector: true, hasContactSelector: false, title: presentationData.strings.WebApp_SelectChat)) controller.peerSelected = { peer in - let _ = context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(id: peer.id), attachBotStart: ChatControllerInitialAttachBotStart(botId: botPeer.id, payload: payload), useExisting: true)) + let _ = context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(id: peer.id), attachBotStart: ChatControllerInitialAttachBotStart(botId: botPeer.id, payload: payload, justInstalled: true), useExisting: true)) } navigationController.pushViewController(controller) } } else { if let navigationController = navigationController, case let .chat(chatPeerId, _) = urlContext { - let _ = context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(id: chatPeerId), attachBotStart: ChatControllerInitialAttachBotStart(botId: botPeer.id, payload: payload), useExisting: true)) + let _ = context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(id: chatPeerId), attachBotStart: ChatControllerInitialAttachBotStart(botId: botPeer.id, payload: payload, justInstalled: true), useExisting: true)) } } }) diff --git a/submodules/TelegramUI/Sources/OpenUrl.swift b/submodules/TelegramUI/Sources/OpenUrl.swift index 29e075649e..8ccabf6e46 100644 --- a/submodules/TelegramUI/Sources/OpenUrl.swift +++ b/submodules/TelegramUI/Sources/OpenUrl.swift @@ -647,6 +647,7 @@ func openExternalUrlImpl(context: AccountContext, urlContext: OpenURLContext, ur var domain: String? var start: String? var startGroup: String? + var startChannel: String? var admin: String? var game: String? var post: String? @@ -684,6 +685,10 @@ func openExternalUrlImpl(context: AccountContext, urlContext: OpenURLContext, ur voiceChat = "" } else if queryItem.name == "startattach" { startAttach = "" + } else if queryItem.name == "startgroup" { + startGroup = "" + } else if queryItem.name == "startchannel" { + startChannel = "" } } } @@ -698,7 +703,20 @@ func openExternalUrlImpl(context: AccountContext, urlContext: OpenURLContext, ur if let start = start { result += "?start=\(start)" } else if let startGroup = startGroup { - result += "?startgroup=\(startGroup)" + if !startGroup.isEmpty { + result += "?startgroup=\(startGroup)" + } else { + result += "?startgroup" + } + if let admin = admin { + result += "&admin=\(admin)" + } + } else if let startChannel = startChannel { + if !startChannel.isEmpty { + result += "?startchannel=\(startChannel)" + } else { + result += "?startchannel" + } if let admin = admin { result += "&admin=\(admin)" } diff --git a/submodules/UrlHandling/Sources/UrlHandling.swift b/submodules/UrlHandling/Sources/UrlHandling.swift index 6845840629..4baca26a92 100644 --- a/submodules/UrlHandling/Sources/UrlHandling.swift +++ b/submodules/UrlHandling/Sources/UrlHandling.swift @@ -230,6 +230,15 @@ public func parseInternalUrl(query: String) -> ParsedInternalUrl? { } } return .startAttach(peerName, nil, choose) + } else if queryItem.name == "startgroup" || queryItem.name == "startchannel" { + var botAdminRights: ResolvedBotAdminRights? + for queryItem in queryItems { + if queryItem.name == "admin", let value = queryItem.value { + botAdminRights = ResolvedBotAdminRights(value) + break + } + } + return .peerName(peerName, .groupBotStart("", botAdminRights)) } } } @@ -468,7 +477,7 @@ private func resolveInternalUrl(context: AccountContext, url: ParsedInternalUrl) |> take(1) |> map { botPeer -> ResolvedUrl? in if let botPeer = botPeer?._asPeer() { - return .peer(peer.id, .withAttachBot(ChatControllerInitialAttachBotStart(botId: botPeer.id, payload: startAttach))) + return .peer(peer.id, .withAttachBot(ChatControllerInitialAttachBotStart(botId: botPeer.id, payload: startAttach, justInstalled: false))) } else { return .peer(peer.id, .chat(textInputState: nil, subject: nil, peekData: nil)) } @@ -502,7 +511,7 @@ private func resolveInternalUrl(context: AccountContext, url: ParsedInternalUrl) } |> mapToSignal { botPeer -> Signal in if let botPeer = botPeer { - return .single(.peer(peer.id, .withAttachBot(ChatControllerInitialAttachBotStart(botId: botPeer.id, payload: payload)))) + return .single(.peer(peer.id, .withAttachBot(ChatControllerInitialAttachBotStart(botId: botPeer.id, payload: payload, justInstalled: false)))) } else { return .single(.peer(peer.id, .chat(textInputState: nil, subject: nil, peekData: nil))) }