diff --git a/Telegram/Telegram-iOS/en.lproj/Localizable.strings b/Telegram/Telegram-iOS/en.lproj/Localizable.strings index a2303f8781..41502d52e8 100644 --- a/Telegram/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram/Telegram-iOS/en.lproj/Localizable.strings @@ -16217,3 +16217,18 @@ Error: %8$@"; "Chat.AdminAction.ToastReactionsDeletedTextSingle" = "Reaction Deleted."; "Chat.AdminAction.ToastReactionsDeletedTextMultiple" = "Reactions Deleted."; "Chat.AdminAction.ToastMessagesAndReactionsDeletedText" = "Messages and reactions deleted."; + +"Premium.SignUp.SignUpNewInfo" = "Get Telegram Premium for %@"; +"Premium.SignUp.SignUpNewInfo.Days_1" = "%@ day"; +"Premium.SignUp.SignUpNewInfo.Days_any" = "%@ days"; +"Premium.SignUp.SignUpNewInfoNone" = "Get Telegram Premium"; + +"Login.Fee.Support.NewText.Days_1" = "%@ day"; +"Login.Fee.Support.NewText.Days_any" = "%@ days"; +"Login.Fee.Support.NewText" = "Sign up for a %@ Telegram Premium subscription to help cover the SMS costs."; +"Login.Fee.Support.NewTextNone" = "Sign up for Telegram Premium subscription to help cover the SMS costs."; + +"Login.Fee.GetPremiumNone" = "Get Telegram Premium"; +"Login.Fee.GetPremiumForDays" = "Get Telegram Premium for %@"; +"Login.Fee.GetPremiumForDays.Days_1" = "%@ day"; +"Login.Fee.GetPremiumForDays.Days_any" = "%@ days"; diff --git a/submodules/AccountContext/Sources/Premium.swift b/submodules/AccountContext/Sources/Premium.swift index cfce7d1d14..359d11a4ba 100644 --- a/submodules/AccountContext/Sources/Premium.swift +++ b/submodules/AccountContext/Sources/Premium.swift @@ -45,7 +45,7 @@ public enum PremiumIntroSource { case todo case copyProtection case aiTools - case auth(String) + case auth(String, Int32) case premiumGift(TelegramMediaFile) } diff --git a/submodules/AuthorizationUI/Sources/AuthorizationSequenceController.swift b/submodules/AuthorizationUI/Sources/AuthorizationSequenceController.swift index 313d21980a..1b4da5efdc 100644 --- a/submodules/AuthorizationUI/Sources/AuthorizationSequenceController.swift +++ b/submodules/AuthorizationUI/Sources/AuthorizationSequenceController.swift @@ -810,8 +810,8 @@ public final class AuthorizationSequenceController: NavigationController, ASAuth return controller } - private func paymentController(number: String, phoneCodeHash: String, storeProduct: String, supportEmailAddress: String, supportEmailSubject: String) -> AuthorizationSequencePaymentScreen { - let controller = AuthorizationSequencePaymentScreen(sharedContext: self.sharedContext, engine: self.engine, presentationData: self.presentationData, inAppPurchaseManager: self.inAppPurchaseManager, phoneNumber: number, phoneCodeHash: phoneCodeHash, storeProduct: storeProduct, supportEmailAddress: supportEmailAddress, supportEmailSubject: supportEmailSubject, back: { [weak self] in + private func paymentController(number: String, phoneCodeHash: String, storeProduct: String, premiumDays: Int32, supportEmailAddress: String, supportEmailSubject: String) -> AuthorizationSequencePaymentScreen { + let controller = AuthorizationSequencePaymentScreen(sharedContext: self.sharedContext, engine: self.engine, presentationData: self.presentationData, inAppPurchaseManager: self.inAppPurchaseManager, phoneNumber: number, phoneCodeHash: phoneCodeHash, storeProduct: storeProduct, premiumDays: premiumDays, supportEmailAddress: supportEmailAddress, supportEmailSubject: supportEmailSubject, back: { [weak self] in guard let self else { return } @@ -1348,12 +1348,12 @@ public final class AuthorizationSequenceController: NavigationController, ASAuth } controllers.append(self.signUpController(firstName: firstName, lastName: lastName, termsOfService: termsOfService, displayCancel: displayCancel)) self.setViewControllers(controllers, animated: !self.viewControllers.isEmpty) - case let .payment(number, codeHash, storeProduct, supportEmailAddress, supportEmailSubject, _): + case let .payment(number, codeHash, storeProduct, premiumDays, supportEmailAddress, supportEmailSubject, _): var controllers: [ViewController] = [] if !self.otherAccountPhoneNumbers.1.isEmpty { controllers.append(self.splashController()) } - controllers.append(self.paymentController(number: number, phoneCodeHash: codeHash, storeProduct: storeProduct, supportEmailAddress: supportEmailAddress, supportEmailSubject: supportEmailSubject)) + controllers.append(self.paymentController(number: number, phoneCodeHash: codeHash, storeProduct: storeProduct, premiumDays: premiumDays, supportEmailAddress: supportEmailAddress, supportEmailSubject: supportEmailSubject)) self.setViewControllers(controllers, animated: !self.viewControllers.isEmpty) } } diff --git a/submodules/AuthorizationUI/Sources/AuthorizationSequencePaymentScreen.swift b/submodules/AuthorizationUI/Sources/AuthorizationSequencePaymentScreen.swift index 07fe4c61f9..8658893b75 100644 --- a/submodules/AuthorizationUI/Sources/AuthorizationSequencePaymentScreen.swift +++ b/submodules/AuthorizationUI/Sources/AuthorizationSequencePaymentScreen.swift @@ -39,6 +39,7 @@ final class AuthorizationSequencePaymentScreenComponent: Component { let phoneNumber: String let phoneCodeHash: String let storeProduct: String + let premiumDays: Int32 let supportEmailAddress: String let supportEmailSubject: String @@ -50,6 +51,7 @@ final class AuthorizationSequencePaymentScreenComponent: Component { phoneNumber: String, phoneCodeHash: String, storeProduct: String, + premiumDays: Int32, supportEmailAddress: String, supportEmailSubject: String ) { @@ -60,6 +62,7 @@ final class AuthorizationSequencePaymentScreenComponent: Component { self.phoneNumber = phoneNumber self.phoneCodeHash = phoneCodeHash self.storeProduct = storeProduct + self.premiumDays = premiumDays self.supportEmailAddress = supportEmailAddress self.supportEmailSubject = supportEmailSubject } @@ -115,7 +118,7 @@ final class AuthorizationSequencePaymentScreenComponent: Component { self.state?.updated() let (currency, amount) = storeProduct.priceCurrencyAndAmount - let purpose: AppStoreTransactionPurpose = .authCode(restore: false, phoneNumber: component.phoneNumber, phoneCodeHash: component.phoneCodeHash, currency: currency, amount: amount) + let purpose: AppStoreTransactionPurpose = .authCode(restore: false, phoneNumber: component.phoneNumber, phoneCodeHash: component.phoneCodeHash, premiumDays: component.premiumDays, currency: currency, amount: amount) let _ = (component.engine.payments.canPurchasePremium(purpose: purpose) |> deliverOnMainQueue).start(next: { [weak self] available in guard let self else { @@ -333,13 +336,24 @@ final class AuthorizationSequencePaymentScreenComponent: Component { )) ) ) + + let supportText: String + if component.premiumDays == 7 { + supportText = environment.strings.Login_Fee_Support_Text + } else if component.premiumDays > 0 { + let daysString = environment.strings.Login_Fee_Support_NewText_Days(component.premiumDays) + supportText = environment.strings.Login_Fee_Support_NewText(daysString).string + } else { + supportText = environment.strings.Login_Fee_Support_NewTextNone + } + items.append( AnyComponentWithIdentity( id: "support", component: AnyComponent(ParagraphComponent( title: environment.strings.Login_Fee_Support_Title, titleColor: textColor, - text: environment.strings.Login_Fee_Support_Text, + text: supportText, textColor: secondaryTextColor, iconName: "Premium/Authorization/Support", iconColor: linkColor, @@ -351,7 +365,7 @@ final class AuthorizationSequencePaymentScreenComponent: Component { sharedContext: component.sharedContext, engine: component.engine, inAppPurchaseManager: component.inAppPurchaseManager, - source: .auth(product.price), + source: .auth(product.price, component.premiumDays), proceed: { [weak self] in self?.proceed() } @@ -410,6 +424,16 @@ final class AuthorizationSequencePaymentScreenComponent: Component { } let buttonString = environment.strings.Login_Fee_SignUp(priceString).string + let buttonSubtitle: String + if component.premiumDays == 7 { + buttonSubtitle = environment.strings.Login_Fee_GetPremiumForAWeek + } else if component.premiumDays > 0 { + let daysString = environment.strings.Login_Fee_GetPremiumForDays_Days(component.premiumDays) + buttonSubtitle = environment.strings.Login_Fee_GetPremiumForDays(daysString).string + } else { + buttonSubtitle = environment.strings.Login_Fee_GetPremiumNone + } + let buttonAttributedString = NSMutableAttributedString(string: buttonString, font: Font.semibold(17.0), textColor: environment.theme.list.itemCheckColors.foregroundColor, paragraphAlignment: .center) let buttonSize = self.button.update( transition: transition, @@ -425,7 +449,7 @@ final class AuthorizationSequencePaymentScreenComponent: Component { component: AnyComponent( VStack([ AnyComponentWithIdentity(id: AnyHashable(0), component: AnyComponent(MultilineTextComponent(text: .plain(buttonAttributedString)))), - AnyComponentWithIdentity(id: AnyHashable(1), component: AnyComponent(MultilineTextComponent(text: .plain(NSAttributedString(string: environment.strings.Login_Fee_GetPremiumForAWeek, font: Font.medium(11.0), textColor: environment.theme.list.itemCheckColors.foregroundColor.withAlphaComponent(0.7), paragraphAlignment: .center))))) + AnyComponentWithIdentity(id: AnyHashable(1), component: AnyComponent(MultilineTextComponent(text: .plain(NSAttributedString(string: buttonSubtitle, font: Font.medium(11.0), textColor: environment.theme.list.itemCheckColors.foregroundColor.withAlphaComponent(0.7), paragraphAlignment: .center))))) ], spacing: 1.0) ) ), @@ -467,6 +491,7 @@ public final class AuthorizationSequencePaymentScreen: ViewControllerComponentCo phoneNumber: String, phoneCodeHash: String, storeProduct: String, + premiumDays: Int32, supportEmailAddress: String, supportEmailSubject: String, back: @escaping () -> Void @@ -479,6 +504,7 @@ public final class AuthorizationSequencePaymentScreen: ViewControllerComponentCo phoneNumber: phoneNumber, phoneCodeHash: phoneCodeHash, storeProduct: storeProduct, + premiumDays: premiumDays, supportEmailAddress: supportEmailAddress, supportEmailSubject: supportEmailSubject ), navigationBarAppearance: .transparent, theme: .default, updatedPresentationData: (initial: presentationData, signal: .single(presentationData))) diff --git a/submodules/BrowserUI/Sources/BrowserMarkdown.swift b/submodules/BrowserUI/Sources/BrowserMarkdown.swift index 17dbb5dc35..6ef7a0eea5 100644 --- a/submodules/BrowserUI/Sources/BrowserMarkdown.swift +++ b/submodules/BrowserUI/Sources/BrowserMarkdown.swift @@ -42,7 +42,7 @@ private let markdownVoidHTMLTags: Set = [ ] private struct MarkdownSafetyLimits { - let maxFileSize = 2_097_152 + let maxFileSize = 524_288 let maxLineLength = 32_768 let maxBlockquoteDepth = 64 let maxListIndent = 96 diff --git a/submodules/InAppPurchaseManager/Sources/InAppPurchaseManager.swift b/submodules/InAppPurchaseManager/Sources/InAppPurchaseManager.swift index 8929b51249..74f3824243 100644 --- a/submodules/InAppPurchaseManager/Sources/InAppPurchaseManager.swift +++ b/submodules/InAppPurchaseManager/Sources/InAppPurchaseManager.swift @@ -662,6 +662,7 @@ private final class PendingInAppPurchaseState: Codable { case restore case phoneNumber case phoneCodeHash + case premiumDays } enum PurposeType: Int32 { @@ -686,7 +687,7 @@ private final class PendingInAppPurchaseState: Codable { case stars(count: Int64, peerId: EnginePeer.Id?) case starsGift(peerId: EnginePeer.Id, count: Int64) case starsGiveaway(stars: Int64, boostPeer: EnginePeer.Id, additionalPeerIds: [EnginePeer.Id], countries: [String], onlyNewSubscribers: Bool, showWinners: Bool, prizeDescription: String?, randomId: Int64, untilDate: Int32, users: Int32) - case authCode(restore: Bool, phoneNumber: String, phoneCodeHash: String) + case authCode(restore: Bool, phoneNumber: String, phoneCodeHash: String, premiumDays: Int32) public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) @@ -748,7 +749,8 @@ private final class PendingInAppPurchaseState: Codable { self = .authCode( restore: try container.decode(Bool.self, forKey: .restore), phoneNumber: try container.decode(String.self, forKey: .phoneNumber), - phoneCodeHash: try container.decode(String.self, forKey: .phoneCodeHash) + phoneCodeHash: try container.decode(String.self, forKey: .phoneCodeHash), + premiumDays: try container.decode(Int32.self, forKey: .premiumDays), ) default: throw DecodingError.generic @@ -804,11 +806,12 @@ private final class PendingInAppPurchaseState: Codable { try container.encode(randomId, forKey: .randomId) try container.encode(untilDate, forKey: .untilDate) try container.encode(users, forKey: .users) - case let .authCode(restore, phoneNumber, phoneCodeHash): + case let .authCode(restore, phoneNumber, phoneCodeHash, premiumDays): try container.encode(PurposeType.authCode.rawValue, forKey: .type) try container.encode(restore, forKey: .restore) try container.encode(phoneNumber, forKey: .phoneNumber) try container.encode(phoneCodeHash, forKey: .phoneCodeHash) + try container.encode(premiumDays, forKey: .premiumDays) } } @@ -832,8 +835,8 @@ private final class PendingInAppPurchaseState: Codable { self = .starsGift(peerId: peerId, count: count) case let .starsGiveaway(stars, boostPeer, additionalPeerIds, countries, onlyNewSubscribers, showWinners, prizeDescription, randomId, untilDate, _, _, users): self = .starsGiveaway(stars: stars, boostPeer: boostPeer, additionalPeerIds: additionalPeerIds, countries: countries, onlyNewSubscribers: onlyNewSubscribers, showWinners: showWinners, prizeDescription: prizeDescription, randomId: randomId, untilDate: untilDate, users: users) - case let .authCode(restore, phoneNumber, phoneCodeHash, _, _): - self = .authCode(restore: restore, phoneNumber: phoneNumber, phoneCodeHash: phoneCodeHash) + case let .authCode(restore, phoneNumber, phoneCodeHash, premiumDays, _, _): + self = .authCode(restore: restore, phoneNumber: phoneNumber, phoneCodeHash: phoneCodeHash, premiumDays: premiumDays) } } @@ -858,8 +861,8 @@ private final class PendingInAppPurchaseState: Codable { return .starsGift(peerId: peerId, count: count, currency: currency, amount: amount) case let .starsGiveaway(stars, boostPeer, additionalPeerIds, countries, onlyNewSubscribers, showWinners, prizeDescription, randomId, untilDate, users): return .starsGiveaway(stars: stars, boostPeer: boostPeer, additionalPeerIds: additionalPeerIds, countries: countries, onlyNewSubscribers: onlyNewSubscribers, showWinners: showWinners, prizeDescription: prizeDescription, randomId: randomId, untilDate: untilDate, currency: currency, amount: amount, users: users) - case let .authCode(restore, phoneNumber, phoneCodeHash): - return .authCode(restore: restore, phoneNumber: phoneNumber, phoneCodeHash: phoneCodeHash, currency: currency, amount: amount) + case let .authCode(restore, phoneNumber, phoneCodeHash, premiumDays): + return .authCode(restore: restore, phoneNumber: phoneNumber, phoneCodeHash: phoneCodeHash, premiumDays: premiumDays, currency: currency, amount: amount) } } } diff --git a/submodules/PremiumUI/Sources/PremiumIntroScreen.swift b/submodules/PremiumUI/Sources/PremiumIntroScreen.swift index 7eabf03dfd..d4bef601c4 100644 --- a/submodules/PremiumUI/Sources/PremiumIntroScreen.swift +++ b/submodules/PremiumUI/Sources/PremiumIntroScreen.swift @@ -329,8 +329,8 @@ public enum PremiumSource: Equatable { } else { return false } - case let .auth(lhsPrice): - if case let .auth(rhsPrice) = rhs, lhsPrice == rhsPrice { + case let .auth(lhsPrice, lhsDays): + if case let .auth(rhsPrice, rhsDays) = rhs, lhsPrice == rhsPrice, lhsDays == rhsDays { return true } else { return false @@ -391,7 +391,7 @@ public enum PremiumSource: Equatable { case todo case copyProtection case aiTools - case auth(String) + case auth(String, Int32) case premiumGift(TelegramMediaFile) var identifier: String? { @@ -3786,9 +3786,16 @@ private final class PremiumIntroScreenComponent: CombinedComponent { if !buttonIsHidden { let buttonTitle: String var buttonSubtitle: String? - if case let .auth(price) = context.component.source { + if case let .auth(price, days) = context.component.source { buttonTitle = environment.strings.Premium_Week_SignUp(price).string - buttonSubtitle = environment.strings.Premium_Week_SignUpInfo + if days == 7 { + buttonSubtitle = environment.strings.Premium_Week_SignUpInfo + } else if days > 0 { + let daysString = environment.strings.Premium_SignUp_SignUpNewInfo_Days(days) + buttonSubtitle = environment.strings.Premium_SignUp_SignUpNewInfo(daysString).string + } else { + buttonSubtitle = environment.strings.Premium_SignUp_SignUpNewInfoNone + } } else if isUnusedGift { buttonTitle = environment.strings.Premium_Gift_ApplyLink } else if state.isPremium == true && state.canUpgrade { diff --git a/submodules/TelegramApi/Sources/Api0.swift b/submodules/TelegramApi/Sources/Api0.swift index b097a2a091..fd0a5e29ee 100644 --- a/submodules/TelegramApi/Sources/Api0.swift +++ b/submodules/TelegramApi/Sources/Api0.swift @@ -518,7 +518,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[853188252] = { return Api.InputStickerSetItem.parse_inputStickerSetItem($0) } dict[70813275] = { return Api.InputStickeredMedia.parse_inputStickeredMediaDocument($0) } dict[1251549527] = { return Api.InputStickeredMedia.parse_inputStickeredMediaPhoto($0) } - dict[-1682807955] = { return Api.InputStorePaymentPurpose.parse_inputStorePaymentAuthCode($0) } + dict[1069645911] = { return Api.InputStorePaymentPurpose.parse_inputStorePaymentAuthCode($0) } dict[1634697192] = { return Api.InputStorePaymentPurpose.parse_inputStorePaymentGiftPremium($0) } dict[-75955309] = { return Api.InputStorePaymentPurpose.parse_inputStorePaymentPremiumGiftCode($0) } dict[369444042] = { return Api.InputStorePaymentPurpose.parse_inputStorePaymentPremiumGiveaway($0) } @@ -1358,7 +1358,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[-503089271] = { return Api.auth.PasskeyLoginOptions.parse_passkeyLoginOptions($0) } dict[326715557] = { return Api.auth.PasswordRecovery.parse_passwordRecovery($0) } dict[1577067778] = { return Api.auth.SentCode.parse_sentCode($0) } - dict[-527082948] = { return Api.auth.SentCode.parse_sentCodePaymentRequired($0) } + dict[-125665601] = { return Api.auth.SentCode.parse_sentCodePaymentRequired($0) } dict[596704836] = { return Api.auth.SentCode.parse_sentCodeSuccess($0) } dict[1035688326] = { return Api.auth.SentCodeType.parse_sentCodeTypeApp($0) } dict[1398007207] = { return Api.auth.SentCodeType.parse_sentCodeTypeCall($0) } diff --git a/submodules/TelegramApi/Sources/Api13.swift b/submodules/TelegramApi/Sources/Api13.swift index 1a0cc1b88c..cd4f464e19 100644 --- a/submodules/TelegramApi/Sources/Api13.swift +++ b/submodules/TelegramApi/Sources/Api13.swift @@ -1209,17 +1209,19 @@ public extension Api { public var flags: Int32 public var phoneNumber: String public var phoneCodeHash: String + public var premiumDays: Int32 public var currency: String public var amount: Int64 - public init(flags: Int32, phoneNumber: String, phoneCodeHash: String, currency: String, amount: Int64) { + public init(flags: Int32, phoneNumber: String, phoneCodeHash: String, premiumDays: Int32, currency: String, amount: Int64) { self.flags = flags self.phoneNumber = phoneNumber self.phoneCodeHash = phoneCodeHash + self.premiumDays = premiumDays self.currency = currency self.amount = amount } public func descriptionFields() -> (String, [(String, ConstructorParameterDescription)]) { - return ("inputStorePaymentAuthCode", [("flags", ConstructorParameterDescription(self.flags)), ("phoneNumber", ConstructorParameterDescription(self.phoneNumber)), ("phoneCodeHash", ConstructorParameterDescription(self.phoneCodeHash)), ("currency", ConstructorParameterDescription(self.currency)), ("amount", ConstructorParameterDescription(self.amount))]) + return ("inputStorePaymentAuthCode", [("flags", ConstructorParameterDescription(self.flags)), ("phoneNumber", ConstructorParameterDescription(self.phoneNumber)), ("phoneCodeHash", ConstructorParameterDescription(self.phoneCodeHash)), ("premiumDays", ConstructorParameterDescription(self.premiumDays)), ("currency", ConstructorParameterDescription(self.currency)), ("amount", ConstructorParameterDescription(self.amount))]) } } public class Cons_inputStorePaymentGiftPremium: TypeConstructorDescription { @@ -1362,11 +1364,12 @@ public extension Api { switch self { case .inputStorePaymentAuthCode(let _data): if boxed { - buffer.appendInt32(-1682807955) + buffer.appendInt32(1069645911) } serializeInt32(_data.flags, buffer: buffer, boxed: false) serializeString(_data.phoneNumber, buffer: buffer, boxed: false) serializeString(_data.phoneCodeHash, buffer: buffer, boxed: false) + serializeInt32(_data.premiumDays, buffer: buffer, boxed: false) serializeString(_data.currency, buffer: buffer, boxed: false) serializeInt64(_data.amount, buffer: buffer, boxed: false) break @@ -1488,7 +1491,7 @@ public extension Api { public func descriptionFields() -> (String, [(String, ConstructorParameterDescription)]) { switch self { case .inputStorePaymentAuthCode(let _data): - return ("inputStorePaymentAuthCode", [("flags", ConstructorParameterDescription(_data.flags)), ("phoneNumber", ConstructorParameterDescription(_data.phoneNumber)), ("phoneCodeHash", ConstructorParameterDescription(_data.phoneCodeHash)), ("currency", ConstructorParameterDescription(_data.currency)), ("amount", ConstructorParameterDescription(_data.amount))]) + return ("inputStorePaymentAuthCode", [("flags", ConstructorParameterDescription(_data.flags)), ("phoneNumber", ConstructorParameterDescription(_data.phoneNumber)), ("phoneCodeHash", ConstructorParameterDescription(_data.phoneCodeHash)), ("premiumDays", ConstructorParameterDescription(_data.premiumDays)), ("currency", ConstructorParameterDescription(_data.currency)), ("amount", ConstructorParameterDescription(_data.amount))]) case .inputStorePaymentGiftPremium(let _data): return ("inputStorePaymentGiftPremium", [("userId", ConstructorParameterDescription(_data.userId)), ("currency", ConstructorParameterDescription(_data.currency)), ("amount", ConstructorParameterDescription(_data.amount))]) case .inputStorePaymentPremiumGiftCode(let _data): @@ -1513,17 +1516,20 @@ public extension Api { _2 = parseString(reader) var _3: String? _3 = parseString(reader) - var _4: String? - _4 = parseString(reader) - var _5: Int64? - _5 = reader.readInt64() + var _4: Int32? + _4 = reader.readInt32() + var _5: String? + _5 = parseString(reader) + var _6: Int64? + _6 = reader.readInt64() let _c1 = _1 != nil let _c2 = _2 != nil let _c3 = _3 != nil let _c4 = _4 != nil let _c5 = _5 != nil - if _c1 && _c2 && _c3 && _c4 && _c5 { - return Api.InputStorePaymentPurpose.inputStorePaymentAuthCode(Cons_inputStorePaymentAuthCode(flags: _1!, phoneNumber: _2!, phoneCodeHash: _3!, currency: _4!, amount: _5!)) + let _c6 = _6 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 { + return Api.InputStorePaymentPurpose.inputStorePaymentAuthCode(Cons_inputStorePaymentAuthCode(flags: _1!, phoneNumber: _2!, phoneCodeHash: _3!, premiumDays: _4!, currency: _5!, amount: _6!)) } else { return nil diff --git a/submodules/TelegramApi/Sources/Api31.swift b/submodules/TelegramApi/Sources/Api31.swift index ddecedb633..4e02876037 100644 --- a/submodules/TelegramApi/Sources/Api31.swift +++ b/submodules/TelegramApi/Sources/Api31.swift @@ -1227,18 +1227,20 @@ public extension Api.auth { public var phoneCodeHash: String public var supportEmailAddress: String public var supportEmailSubject: String + public var premiumDays: Int32 public var currency: String public var amount: Int64 - public init(storeProduct: String, phoneCodeHash: String, supportEmailAddress: String, supportEmailSubject: String, currency: String, amount: Int64) { + public init(storeProduct: String, phoneCodeHash: String, supportEmailAddress: String, supportEmailSubject: String, premiumDays: Int32, currency: String, amount: Int64) { self.storeProduct = storeProduct self.phoneCodeHash = phoneCodeHash self.supportEmailAddress = supportEmailAddress self.supportEmailSubject = supportEmailSubject + self.premiumDays = premiumDays self.currency = currency self.amount = amount } public func descriptionFields() -> (String, [(String, ConstructorParameterDescription)]) { - return ("sentCodePaymentRequired", [("storeProduct", ConstructorParameterDescription(self.storeProduct)), ("phoneCodeHash", ConstructorParameterDescription(self.phoneCodeHash)), ("supportEmailAddress", ConstructorParameterDescription(self.supportEmailAddress)), ("supportEmailSubject", ConstructorParameterDescription(self.supportEmailSubject)), ("currency", ConstructorParameterDescription(self.currency)), ("amount", ConstructorParameterDescription(self.amount))]) + return ("sentCodePaymentRequired", [("storeProduct", ConstructorParameterDescription(self.storeProduct)), ("phoneCodeHash", ConstructorParameterDescription(self.phoneCodeHash)), ("supportEmailAddress", ConstructorParameterDescription(self.supportEmailAddress)), ("supportEmailSubject", ConstructorParameterDescription(self.supportEmailSubject)), ("premiumDays", ConstructorParameterDescription(self.premiumDays)), ("currency", ConstructorParameterDescription(self.currency)), ("amount", ConstructorParameterDescription(self.amount))]) } } public class Cons_sentCodeSuccess: TypeConstructorDescription { @@ -1272,12 +1274,13 @@ public extension Api.auth { break case .sentCodePaymentRequired(let _data): if boxed { - buffer.appendInt32(-527082948) + buffer.appendInt32(-125665601) } serializeString(_data.storeProduct, buffer: buffer, boxed: false) serializeString(_data.phoneCodeHash, buffer: buffer, boxed: false) serializeString(_data.supportEmailAddress, buffer: buffer, boxed: false) serializeString(_data.supportEmailSubject, buffer: buffer, boxed: false) + serializeInt32(_data.premiumDays, buffer: buffer, boxed: false) serializeString(_data.currency, buffer: buffer, boxed: false) serializeInt64(_data.amount, buffer: buffer, boxed: false) break @@ -1295,7 +1298,7 @@ public extension Api.auth { case .sentCode(let _data): return ("sentCode", [("flags", ConstructorParameterDescription(_data.flags)), ("type", ConstructorParameterDescription(_data.type)), ("phoneCodeHash", ConstructorParameterDescription(_data.phoneCodeHash)), ("nextType", ConstructorParameterDescription(_data.nextType)), ("timeout", ConstructorParameterDescription(_data.timeout))]) case .sentCodePaymentRequired(let _data): - return ("sentCodePaymentRequired", [("storeProduct", ConstructorParameterDescription(_data.storeProduct)), ("phoneCodeHash", ConstructorParameterDescription(_data.phoneCodeHash)), ("supportEmailAddress", ConstructorParameterDescription(_data.supportEmailAddress)), ("supportEmailSubject", ConstructorParameterDescription(_data.supportEmailSubject)), ("currency", ConstructorParameterDescription(_data.currency)), ("amount", ConstructorParameterDescription(_data.amount))]) + return ("sentCodePaymentRequired", [("storeProduct", ConstructorParameterDescription(_data.storeProduct)), ("phoneCodeHash", ConstructorParameterDescription(_data.phoneCodeHash)), ("supportEmailAddress", ConstructorParameterDescription(_data.supportEmailAddress)), ("supportEmailSubject", ConstructorParameterDescription(_data.supportEmailSubject)), ("premiumDays", ConstructorParameterDescription(_data.premiumDays)), ("currency", ConstructorParameterDescription(_data.currency)), ("amount", ConstructorParameterDescription(_data.amount))]) case .sentCodeSuccess(let _data): return ("sentCodeSuccess", [("authorization", ConstructorParameterDescription(_data.authorization))]) } @@ -1341,18 +1344,21 @@ public extension Api.auth { _3 = parseString(reader) var _4: String? _4 = parseString(reader) - var _5: String? - _5 = parseString(reader) - var _6: Int64? - _6 = reader.readInt64() + var _5: Int32? + _5 = reader.readInt32() + var _6: String? + _6 = parseString(reader) + var _7: Int64? + _7 = reader.readInt64() let _c1 = _1 != nil let _c2 = _2 != nil let _c3 = _3 != nil let _c4 = _4 != nil let _c5 = _5 != nil let _c6 = _6 != nil - if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 { - return Api.auth.SentCode.sentCodePaymentRequired(Cons_sentCodePaymentRequired(storeProduct: _1!, phoneCodeHash: _2!, supportEmailAddress: _3!, supportEmailSubject: _4!, currency: _5!, amount: _6!)) + let _c7 = _7 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 { + return Api.auth.SentCode.sentCodePaymentRequired(Cons_sentCodePaymentRequired(storeProduct: _1!, phoneCodeHash: _2!, supportEmailAddress: _3!, supportEmailSubject: _4!, premiumDays: _5!, currency: _6!, amount: _7!)) } else { return nil diff --git a/submodules/TelegramApi/Sources/Api40.swift b/submodules/TelegramApi/Sources/Api40.swift index a872989b8d..27a36a3d77 100644 --- a/submodules/TelegramApi/Sources/Api40.swift +++ b/submodules/TelegramApi/Sources/Api40.swift @@ -103,6 +103,21 @@ public extension Api.functions.account { }) } } +public extension Api.functions.account { + static func confirmBotConnection(botId: Api.InputUser) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(1743593320) + botId.serialize(buffer, true) + return (FunctionDescription(name: "account.confirmBotConnection", parameters: [("botId", ConstructorParameterDescription(botId))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } +} public extension Api.functions.account { static func confirmPasswordEmail(code: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { let buffer = Buffer() diff --git a/submodules/TelegramCore/Sources/Account/Account.swift b/submodules/TelegramCore/Sources/Account/Account.swift index ee663bb5aa..232b84e1e8 100644 --- a/submodules/TelegramCore/Sources/Account/Account.swift +++ b/submodules/TelegramCore/Sources/Account/Account.swift @@ -128,7 +128,7 @@ public class UnauthorizedAccount { if let nextType = nextType { parsedNextType = AuthorizationCodeNextType(apiType: nextType) } - if let state = transaction.getState() as? UnauthorizedAccountState, case let .payment(phoneNumber, _, _, _, _, syncContacts) = state.contents { + if let state = transaction.getState() as? UnauthorizedAccountState, case let .payment(phoneNumber, _, _, _, _, _, syncContacts) = state.contents { transaction.setState(UnauthorizedAccountState(isTestingEnvironment: testingEnvironment, masterDatacenterId: masterDatacenterId, contents: .confirmationCodeEntry(number: phoneNumber, type: SentAuthorizationCodeType(apiType: type), hash: phoneCodeHash, timeout: codeTimeout, nextType: parsedNextType, syncContacts: syncContacts, previousCodeEntry: nil, usePrevious: false))) } }).start() @@ -139,7 +139,7 @@ public class UnauthorizedAccount { let (futureAuthToken, apiUser) = (authorizationData.futureAuthToken, authorizationData.user) let _ = postbox.transaction({ [weak self] transaction in var syncContacts = true - if let state = transaction.getState() as? UnauthorizedAccountState, case let .payment(_, _, _, _, _, syncContactsValue) = state.contents { + if let state = transaction.getState() as? UnauthorizedAccountState, case let .payment(_, _, _, _, _, _, syncContactsValue) = state.contents { syncContacts = syncContactsValue } @@ -166,7 +166,7 @@ public class UnauthorizedAccount { let termsOfService = authorizationSignUpRequiredData.termsOfService let _ = postbox.transaction({ [weak self] transaction in if let self { - if let state = transaction.getState() as? UnauthorizedAccountState, case let .payment(number, codeHash, _, _, _, syncContacts) = state.contents { + if let state = transaction.getState() as? UnauthorizedAccountState, case let .payment(number, codeHash, _, _, _, _, syncContacts) = state.contents { let _ = beginSignUp( account: self, data: AuthorizationSignUpData( diff --git a/submodules/TelegramCore/Sources/Authorization.swift b/submodules/TelegramCore/Sources/Authorization.swift index 25caa0afc8..5bc16112de 100644 --- a/submodules/TelegramCore/Sources/Authorization.swift +++ b/submodules/TelegramCore/Sources/Authorization.swift @@ -527,8 +527,8 @@ private func internalResendAuthorizationCode(accountManager: AccountManager Signal { @@ -155,12 +155,12 @@ private func apiInputStorePaymentPurpose(postbox: Postbox, purpose: AppStoreTran return .single(.inputStorePaymentStarsGiveaway(.init(flags: flags, stars: stars, boostPeer: apiBoostPeer, additionalPeers: additionalPeers, countriesIso2: countries, prizeDescription: prizeDescription, randomId: randomId, untilDate: untilDate, currency: currency, amount: amount, users: users))) } |> switchToLatest - case let .authCode(restore, phoneNumber, phoneCodeHash, currency, amount): + case let .authCode(restore, phoneNumber, phoneCodeHash, premiumDays, currency, amount): var flags: Int32 = 0 if restore { flags |= (1 << 0) } - return .single(.inputStorePaymentAuthCode(.init(flags: flags, phoneNumber: phoneNumber, phoneCodeHash: phoneCodeHash, currency: currency, amount: amount))) + return .single(.inputStorePaymentAuthCode(.init(flags: flags, phoneNumber: phoneNumber, phoneCodeHash: phoneCodeHash, premiumDays: premiumDays, currency: currency, amount: amount))) } } diff --git a/submodules/TelegramUI/Components/ComposeTodoScreen/Sources/ComposeTodoScreen.swift b/submodules/TelegramUI/Components/ComposeTodoScreen/Sources/ComposeTodoScreen.swift index 3002238bac..5eb51a3f78 100644 --- a/submodules/TelegramUI/Components/ComposeTodoScreen/Sources/ComposeTodoScreen.swift +++ b/submodules/TelegramUI/Components/ComposeTodoScreen/Sources/ComposeTodoScreen.swift @@ -204,7 +204,7 @@ final class ComposeTodoScreenComponent: Component { for (id, itemView) in self.todoItemsSectionContainer.itemViews { if let view = itemView.contents.view as? ListComposePollOptionComponent.View, !view.isRevealed && !view.currentText.isEmpty { let viewFrame = view.convert(view.bounds, to: self.todoItemsSectionContainer) - let iconFrame = CGRect(origin: CGPoint(x: viewFrame.maxX - 40.0, y: viewFrame.minY), size: CGSize(width: viewFrame.height, height: viewFrame.height)) + let iconFrame = CGRect(origin: CGPoint(x: viewFrame.minX, y: viewFrame.minY), size: CGSize(width: 50.0, height: viewFrame.height)) if iconFrame.contains(localPoint) { return (id, itemView.contents) } diff --git a/submodules/TelegramUI/Components/Gifts/GiftItemComponent/Sources/GiftItemComponent.swift b/submodules/TelegramUI/Components/Gifts/GiftItemComponent/Sources/GiftItemComponent.swift index 840df9d0fb..73e329bf11 100644 --- a/submodules/TelegramUI/Components/Gifts/GiftItemComponent/Sources/GiftItemComponent.swift +++ b/submodules/TelegramUI/Components/Gifts/GiftItemComponent/Sources/GiftItemComponent.swift @@ -345,6 +345,7 @@ public final class GiftItemComponent: Component { private var selectionLayer: SimpleShapeLayer? private var checkLayer: CheckLayer? private var outlineLayer: SimpleLayer? + private var outlineRenderState: OutlineRenderState? private var animationFile: TelegramMediaFile? @@ -361,6 +362,14 @@ public final class GiftItemComponent: Component { private var giftAuctionTimer: SwiftSignalKit.Timer? + private struct OutlineRenderState: Equatable { + let size: CGSize + let cornerRadius: CGFloat + let outline: GiftItemComponent.Outline + let hasRibbon: Bool + let themeId: ObjectIdentifier + } + public var pattern: UIView? { if let view = self.patternView.view { return view @@ -1537,6 +1546,14 @@ public final class GiftItemComponent: Component { if let outline = component.outline { let lineWidth: CGFloat = 2.0 let outlineFrame = backgroundFrame + let hasRibbon = self.ribbon.layer.superlayer != nil + let outlineRenderState = OutlineRenderState( + size: outlineFrame.size, + cornerRadius: cornerRadius, + outline: outline, + hasRibbon: hasRibbon, + themeId: ObjectIdentifier(component.theme) + ) let outlineLayer: SimpleLayer if let current = self.outlineLayer { @@ -1544,12 +1561,15 @@ public final class GiftItemComponent: Component { } else { outlineLayer = SimpleLayer() self.outlineLayer = outlineLayer - if self.ribbon.layer.superlayer != nil { - self.layer.insertSublayer(outlineLayer, below: self.ribbon.layer) - } else { - self.layer.addSublayer(outlineLayer) - } - + } + + if hasRibbon { + self.layer.insertSublayer(outlineLayer, below: self.ribbon.layer) + } else if outlineLayer.superlayer == nil { + self.layer.addSublayer(outlineLayer) + } + + if self.outlineRenderState != outlineRenderState { let image = generateImage(outlineFrame.size, rotatedContext: { size, context in context.clear(CGRect(origin: .zero, size: size)) @@ -1588,11 +1608,13 @@ public final class GiftItemComponent: Component { } }) outlineLayer.contents = image?.cgImage - - outlineLayer.frame = outlineFrame + self.outlineRenderState = outlineRenderState } + + transition.setFrame(layer: outlineLayer, frame: outlineFrame) } else if let outlineLayer = self.outlineLayer { self.outlineLayer = nil + self.outlineRenderState = nil outlineLayer.removeFromSuperlayer() } diff --git a/submodules/TelegramUI/Components/Settings/ChatbotSetupScreen/Sources/ChatbotSetupScreen.swift b/submodules/TelegramUI/Components/Settings/ChatbotSetupScreen/Sources/ChatbotSetupScreen.swift index 1da0fd8d81..8020a1a2f4 100644 --- a/submodules/TelegramUI/Components/Settings/ChatbotSetupScreen/Sources/ChatbotSetupScreen.swift +++ b/submodules/TelegramUI/Components/Settings/ChatbotSetupScreen/Sources/ChatbotSetupScreen.swift @@ -698,13 +698,13 @@ final class ChatbotSetupScreenComponent: Component { let iconSize = self.icon.update( transition: .immediate, component: AnyComponent(LottieComponent( - content: LottieComponent.AppBundleContent(name: "BotEmoji"), + content: LottieComponent.AppBundleContent(name: "ChatAutomation"), loop: false )), environment: {}, - containerSize: CGSize(width: 100.0, height: 100.0) + containerSize: CGSize(width: 140.0, height: 140.0) ) - let iconFrame = CGRect(origin: CGPoint(x: floor((availableSize.width - iconSize.width) * 0.5), y: contentHeight - 30.0), size: iconSize) + let iconFrame = CGRect(origin: CGPoint(x: floor((availableSize.width - iconSize.width) * 0.5), y: contentHeight - 50.0), size: iconSize) if let iconView = self.icon.view as? LottieComponent.View { if iconView.superview == nil { self.scrollView.addSubview(iconView) diff --git a/submodules/TelegramUI/Resources/Animations/BotEmoji.tgs b/submodules/TelegramUI/Resources/Animations/BotEmoji.tgs deleted file mode 100644 index 0076344f4c..0000000000 Binary files a/submodules/TelegramUI/Resources/Animations/BotEmoji.tgs and /dev/null differ diff --git a/submodules/TelegramUI/Resources/Animations/ChatAutomation.tgs b/submodules/TelegramUI/Resources/Animations/ChatAutomation.tgs new file mode 100644 index 0000000000..3e386fd63e Binary files /dev/null and b/submodules/TelegramUI/Resources/Animations/ChatAutomation.tgs differ diff --git a/submodules/TelegramUI/Sources/Chat/ChatControllerLoadDisplayNode.swift b/submodules/TelegramUI/Sources/Chat/ChatControllerLoadDisplayNode.swift index b36b81a3ca..1934f56d65 100644 --- a/submodules/TelegramUI/Sources/Chat/ChatControllerLoadDisplayNode.swift +++ b/submodules/TelegramUI/Sources/Chat/ChatControllerLoadDisplayNode.swift @@ -530,6 +530,8 @@ extension ChatControllerImpl { let initialInterfaceState = contentData.initialInterfaceState contentData.initialInterfaceState = nil + let initialTextInputState = self.initialTextInputState + self.initialTextInputState = nil if !self.didInitializePersistentPeerInterfaceData, let initialPersistentPeerData = contentData.initialPersistentPeerData { self.didInitializePersistentPeerInterfaceData = true @@ -541,6 +543,9 @@ extension ChatControllerImpl { if let initialInterfaceState { interfaceState = initialInterfaceState.interfaceState } + if let initialTextInputState { + interfaceState = interfaceState.withUpdatedComposeInputState(initialTextInputState) + } if let channel = contentData.state.renderedPeer?.peer as? TelegramChannel { if channel.hasBannedPermission(.banSendVoice) != nil && channel.hasBannedPermission(.banSendInstantVideos) != nil { diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index ac67d3c25e..521ea3d5c1 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -252,6 +252,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G let context: AccountContext public internal(set) var chatLocation: ChatLocation public internal(set) var subject: ChatControllerSubject? + var initialTextInputState: ChatTextInputState? var botStart: ChatControllerInitialBotStart? var attachBotStart: ChatControllerInitialAttachBotStart? @@ -642,6 +643,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G chatListFilter: Int32? = nil, chatNavigationStack: [ChatNavigationStackItem] = [], customChatNavigationStack: [EnginePeer.Id]? = nil, + initialTextInputState: ChatTextInputState? = nil, params: ChatControllerParams? = nil ) { self.initTimestamp = CFAbsoluteTimeGetCurrent() @@ -654,6 +656,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G self.chatLocation = chatLocation self.chatLocationContextHolder = chatLocationContextHolder self.subject = subject + self.initialTextInputState = initialTextInputState self.botStart = botStart self.attachBotStart = attachBotStart self.botAppStart = botAppStart diff --git a/submodules/TelegramUI/Sources/ChatInterfaceStateNavigationButtons.swift b/submodules/TelegramUI/Sources/ChatInterfaceStateNavigationButtons.swift index 5c7b6a78e9..c74d28f32b 100644 --- a/submodules/TelegramUI/Sources/ChatInterfaceStateNavigationButtons.swift +++ b/submodules/TelegramUI/Sources/ChatInterfaceStateNavigationButtons.swift @@ -46,12 +46,12 @@ func leftNavigationButtonForChatInterfaceState(_ presentationInterfaceState: Cha } if canClear { - let buttonItem = UIBarButtonItem(title: "___clear", style: .plain, target: target, action: selector) + let buttonItem = UIBarButtonItem(title: strings.Conversation_ClearAll, style: .plain, target: target, action: selector) buttonItem.accessibilityLabel = title return ChatNavigationButton(action: .clearHistory, buttonItem: buttonItem) } else { title = strings.Conversation_ClearCache - let buttonItem = UIBarButtonItem(title: "___clear", style: .plain, target: target, action: selector) + let buttonItem = UIBarButtonItem(title: strings.Conversation_ClearCache, style: .plain, target: target, action: selector) buttonItem.accessibilityLabel = title return ChatNavigationButton(action: .clearCache, buttonItem: buttonItem) } diff --git a/submodules/TelegramUI/Sources/NavigateToChatController.swift b/submodules/TelegramUI/Sources/NavigateToChatController.swift index 60f4344fa0..4f9e8b5f2b 100644 --- a/submodules/TelegramUI/Sources/NavigateToChatController.swift +++ b/submodules/TelegramUI/Sources/NavigateToChatController.swift @@ -253,8 +253,14 @@ public func navigateToChatControllerImpl(_ params: NavigateToChatControllerParam controller.presentBotApp(botApp: botAppStart.botApp, botPeer: peer, payload: botAppStart.payload, mode: botAppStart.mode) } } + + if controller.chatLocation.peerId == params.chatLocation.asChatLocation.peerId && controller.chatLocation.threadId == params.chatLocation.asChatLocation.threadId && (controller.subject != .scheduledMessages || controller.subject == params.subject) { + if let updateTextInputState = params.updateTextInputState { + controller.updateTextInputState(updateTextInputState) + } + } } else { - controller = ChatControllerImpl(context: params.context, chatLocation: params.chatLocation.asChatLocation, chatLocationContextHolder: params.chatLocationContextHolder, subject: params.subject, botStart: params.botStart, attachBotStart: params.attachBotStart, botAppStart: params.botAppStart, peekData: params.peekData, chatListFilter: params.chatListFilter, chatNavigationStack: params.chatNavigationStack, customChatNavigationStack: params.customChatNavigationStack) + controller = ChatControllerImpl(context: params.context, chatLocation: params.chatLocation.asChatLocation, chatLocationContextHolder: params.chatLocationContextHolder, subject: params.subject, botStart: params.botStart, attachBotStart: params.attachBotStart, botAppStart: params.botAppStart, peekData: params.peekData, chatListFilter: params.chatListFilter, chatNavigationStack: params.chatNavigationStack, customChatNavigationStack: params.customChatNavigationStack, initialTextInputState: params.updateTextInputState) if let botAppStart = params.botAppStart, case let .peer(peer) = params.chatLocation { Queue.mainQueue().after(0.1) { @@ -263,14 +269,6 @@ public func navigateToChatControllerImpl(_ params: NavigateToChatControllerParam } } - if controller.chatLocation.peerId == params.chatLocation.asChatLocation.peerId && controller.chatLocation.threadId == params.chatLocation.asChatLocation.threadId && (controller.subject != .scheduledMessages || controller.subject == params.subject) { - if let updateTextInputState = params.updateTextInputState { - Queue.mainQueue().after(0.1) { - controller.updateTextInputState(updateTextInputState) - } - } - } - controller.purposefulAction = params.purposefulAction if let search = params.activateMessageSearch { controller.activateSearch(domain: search.0, query: search.1) @@ -449,7 +447,7 @@ public func navigateToForumThreadImpl(context: AccountContext, peerId: EnginePee } } -public func chatControllerForForumThreadImpl(context: AccountContext, peerId: EnginePeer.Id, threadId: Int64) -> Signal { +public func chatControllerForForumThreadImpl(context: AccountContext, peerId: EnginePeer.Id, threadId: Int64, initialTextInputState: ChatTextInputState? = nil) -> Signal { return context.engine.data.get( TelegramEngine.EngineData.Item.Peer.Peer(id: peerId) ) @@ -477,7 +475,8 @@ public func chatControllerForForumThreadImpl(context: AccountContext, peerId: En initialAnchor: .automatic, isNotAvailable: false )), - chatLocationContextHolder: Atomic(value: nil) + chatLocationContextHolder: Atomic(value: nil), + initialTextInputState: initialTextInputState )) } else { return fetchAndPreloadReplyThreadInfo(context: context, subject: .groupMessage(MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: Int32(clamping: threadId))), atMessageId: nil, preload: false) @@ -489,7 +488,8 @@ public func chatControllerForForumThreadImpl(context: AccountContext, peerId: En return ChatControllerImpl( context: context, chatLocation: .replyThread(message: result.message), - chatLocationContextHolder: result.contextHolder + chatLocationContextHolder: result.contextHolder, + initialTextInputState: initialTextInputState ) } } diff --git a/submodules/TelegramUI/Sources/OpenResolvedUrl.swift b/submodules/TelegramUI/Sources/OpenResolvedUrl.swift index 5d78767dcb..d77a7eb022 100644 --- a/submodules/TelegramUI/Sources/OpenResolvedUrl.swift +++ b/submodules/TelegramUI/Sources/OpenResolvedUrl.swift @@ -20,7 +20,6 @@ import JoinLinkPreviewUI import LanguageLinkPreviewUI import SettingsUI import UrlHandling -import ChatInterfaceState import TelegramCallsUI import UndoUI import ImportStickerPackUI @@ -631,16 +630,16 @@ func openResolvedUrlImpl( } let chatController: Signal if let threadId { - chatController = chatControllerForForumThreadImpl(context: context, peerId: peerId, threadId: threadId) + chatController = chatControllerForForumThreadImpl(context: context, peerId: peerId, threadId: threadId, initialTextInputState: textInputState) } else { - chatController = .single(ChatControllerImpl(context: context, chatLocation: .peer(id: peerId))) + chatController = .single(ChatControllerImpl(context: context, chatLocation: .peer(id: peerId), initialTextInputState: textInputState)) } - + let _ = (chatController |> deliverOnMainQueue).start(next: { [weak navigationController] chatController in guard let navigationController else { return - } + } var controllers = navigationController.viewControllers.filter { controller in if controller is PeerSelectionController { return false @@ -651,17 +650,8 @@ func openResolvedUrlImpl( navigationController.setViewControllers(controllers, animated: true) }) } - - if let textInputState = textInputState { - let _ = (ChatInterfaceState.update(engine: context.engine, peerId: peerId, threadId: threadId, { currentState in - return currentState.withUpdatedComposeInputState(textInputState) - }) - |> deliverOnMainQueue).startStandalone(completed: { - updateControllers() - }) - } else { - updateControllers() - } + + updateControllers() } if let to = to { diff --git a/submodules/TelegramUI/Sources/SharedAccountContext.swift b/submodules/TelegramUI/Sources/SharedAccountContext.swift index 805fade423..2e9920d1fa 100644 --- a/submodules/TelegramUI/Sources/SharedAccountContext.swift +++ b/submodules/TelegramUI/Sources/SharedAccountContext.swift @@ -2975,8 +2975,8 @@ public final class SharedAccountContextImpl: SharedAccountContext { mappedSource = .copyProtection case .aiTools: mappedSource = .aiTools - case let .auth(price): - mappedSource = .auth(price) + case let .auth(price, days): + mappedSource = .auth(price, days) case let .premiumGift(file): mappedSource = .premiumGift(file) } diff --git a/submodules/TextFormat/Sources/ChatTextInputAttributes.swift b/submodules/TextFormat/Sources/ChatTextInputAttributes.swift index 61dde36ecb..75d29e5a3b 100644 --- a/submodules/TextFormat/Sources/ChatTextInputAttributes.swift +++ b/submodules/TextFormat/Sources/ChatTextInputAttributes.swift @@ -604,20 +604,9 @@ private func refreshTextMentions(text: NSString, initialAttributedText: NSAttrib } } -private let textUrlEdgeCharacters: CharacterSet = { - var set: CharacterSet = .alphanumerics - set.formUnion(.symbols) - set.formUnion(.punctuationCharacters) - set.remove("(") - set.remove(")") - return set -}() - -private let textUrlCharacters: CharacterSet = { - var set: CharacterSet = textUrlEdgeCharacters - set.formUnion(.whitespacesAndNewlines) - return set -}() +private func isTextUrlInnerCharacter(_ c: UnicodeScalar) -> Bool { + return alphanumericCharacters.contains(c) || c == " " as UnicodeScalar +} private func refreshTextUrls(text: NSString, initialAttributedText: NSAttributedString, attributedText: NSMutableAttributedString, fullRange: NSRange) { var textUrlRanges: [(NSRange, ChatTextInputTextUrlAttribute)] = [] @@ -635,7 +624,7 @@ private func refreshTextUrls(text: NSString, initialAttributedText: NSAttributed var validLower = range.lowerBound inner1: for i in range.lowerBound ..< range.upperBound { if let c = UnicodeScalar(text.character(at: i)) { - if textUrlCharacters.contains(c) { + if isTextUrlInnerCharacter(c) { validLower = i break inner1 } @@ -646,7 +635,7 @@ private func refreshTextUrls(text: NSString, initialAttributedText: NSAttributed var validUpper = range.upperBound inner2: for i in (validLower ..< range.upperBound).reversed() { if let c = UnicodeScalar(text.character(at: i)) { - if textUrlCharacters.contains(c) { + if isTextUrlInnerCharacter(c) { validUpper = i + 1 break inner2 } @@ -658,7 +647,7 @@ private func refreshTextUrls(text: NSString, initialAttributedText: NSAttributed let minLower = (i == 0) ? fullRange.lowerBound : textUrlRanges[i - 1].0.upperBound inner3: for i in (minLower ..< validLower).reversed() { if let c = UnicodeScalar(text.character(at: i)) { - if textUrlEdgeCharacters.contains(c) { + if alphanumericCharacters.contains(c) { validLower = i } else { break inner3 @@ -671,7 +660,7 @@ private func refreshTextUrls(text: NSString, initialAttributedText: NSAttributed let maxUpper = (i == textUrlRanges.count - 1) ? fullRange.upperBound : textUrlRanges[i + 1].0.lowerBound inner3: for i in validUpper ..< maxUpper { if let c = UnicodeScalar(text.character(at: i)) { - if textUrlEdgeCharacters.contains(c) { + if alphanumericCharacters.contains(c) { validUpper = i + 1 } else { break inner3 @@ -693,7 +682,7 @@ private func refreshTextUrls(text: NSString, initialAttributedText: NSAttributed var combine = true inner: for j in textUrlRanges[i].0.upperBound ..< textUrlRanges[i + 1].0.lowerBound { if let c = UnicodeScalar(text.character(at: j)) { - if textUrlCharacters.contains(c) { + if isTextUrlInnerCharacter(c) { } else { combine = false break inner