diff --git a/Telegram/Telegram-iOS/en.lproj/Localizable.strings b/Telegram/Telegram-iOS/en.lproj/Localizable.strings index df517312fb..f19a36284e 100644 --- a/Telegram/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram/Telegram-iOS/en.lproj/Localizable.strings @@ -9044,7 +9044,7 @@ Sorry for the inconvenience."; "Login.Email.CantAccess" = "Can't access this email?"; "Login.Email.ResetTitle" = "Reset Email"; -"Login.Email.ResetText" = "You can change your login email if you are logged into Telegram from another device. Otherwise, if you don't have access to email %@, you can reset this email with an SMS code in 7 days."; +"Login.Email.ResetText" = "You can change your login email if you are logged into Telegram from another device. Otherwise, if you don't have access to email %1$@, you can reset this email with an **SMS** code **%2$@**."; "Login.Email.Reset" = "Reset"; "Login.Email.ResetNowViaSMS" = "Reset now via SMS"; "Login.Email.WillBeResetIn" = "Email will be reset in %@"; diff --git a/submodules/AlertUI/BUILD b/submodules/AlertUI/BUILD index 9f7f33fd96..2d9a5628f8 100644 --- a/submodules/AlertUI/BUILD +++ b/submodules/AlertUI/BUILD @@ -10,7 +10,10 @@ swift_library( "-warnings-as-errors", ], deps = [ + "//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit", + "//submodules/AsyncDisplayKit:AsyncDisplayKit", "//submodules/Display:Display", + "//submodules/TelegramUI/Components/TextNodeWithEntities:TextNodeWithEntities", ], visibility = [ "//visibility:public", diff --git a/submodules/AlertUI/Sources/TextAlertWithEntitiesController.swift b/submodules/AlertUI/Sources/TextAlertWithEntitiesController.swift new file mode 100644 index 0000000000..a9e506b81c --- /dev/null +++ b/submodules/AlertUI/Sources/TextAlertWithEntitiesController.swift @@ -0,0 +1,355 @@ +import Foundation +import UIKit +import AsyncDisplayKit +import Display +import SwiftSignalKit +import TextNodeWithEntities + +private let alertWidth: CGFloat = 270.0 + +final class TextAlertWithEntitiesContentNode: AlertContentNode { + private var theme: AlertControllerTheme + private let actionLayout: TextAlertContentActionLayout + + private let titleNode: ImmediateTextNode? + private let textNode: ImmediateTextNodeWithEntities + + private let actionNodesSeparator: ASDisplayNode + private let actionNodes: [TextAlertContentActionNode] + private let actionVerticalSeparators: [ASDisplayNode] + + private var validLayout: CGSize? + + private let _dismissOnOutsideTap: Bool + override public var dismissOnOutsideTap: Bool { + return self._dismissOnOutsideTap + } + + private var highlightedItemIndex: Int? = nil + + var textAttributeAction: (NSAttributedString.Key, (Any) -> Void)? { + didSet { + if let (attribute, textAttributeAction) = self.textAttributeAction { + self.textNode.highlightAttributeAction = { attributes in + if let _ = attributes[attribute] { + return attribute + } else { + return nil + } + } + self.textNode.tapAttributeAction = { attributes, _ in + if let value = attributes[attribute] { + textAttributeAction(value) + } + } + self.textNode.linkHighlightColor = self.theme.accentColor.withAlphaComponent(0.5) + } else { + self.textNode.highlightAttributeAction = nil + self.textNode.tapAttributeAction = nil + } + } + } + + init(theme: AlertControllerTheme, title: NSAttributedString?, text: NSAttributedString, actions: [TextAlertAction], actionLayout: TextAlertContentActionLayout, dismissOnOutsideTap: Bool) { + self.theme = theme + self.actionLayout = actionLayout + self._dismissOnOutsideTap = dismissOnOutsideTap + if let title = title { + let titleNode = ImmediateTextNode() + titleNode.attributedText = title + titleNode.displaysAsynchronously = false + titleNode.isUserInteractionEnabled = false + titleNode.maximumNumberOfLines = 4 + titleNode.truncationType = .end + titleNode.isAccessibilityElement = true + titleNode.accessibilityLabel = title.string + self.titleNode = titleNode + } else { + self.titleNode = nil + } + + self.textNode = ImmediateTextNodeWithEntities() + self.textNode.maximumNumberOfLines = 0 + self.textNode.attributedText = text + self.textNode.displaysAsynchronously = false + self.textNode.isLayerBacked = false + self.textNode.isAccessibilityElement = true + self.textNode.accessibilityLabel = text.string + self.textNode.insets = UIEdgeInsets(top: 1.0, left: 1.0, bottom: 1.0, right: 1.0) + if text.length != 0 { + if let paragraphStyle = text.attribute(.paragraphStyle, at: 0, effectiveRange: nil) as? NSParagraphStyle { + self.textNode.textAlignment = paragraphStyle.alignment + } + } + self.textNode.spoilerColor = theme.secondaryColor + + self.actionNodesSeparator = ASDisplayNode() + self.actionNodesSeparator.isLayerBacked = true + self.actionNodesSeparator.backgroundColor = theme.separatorColor + + self.actionNodes = actions.map { action -> TextAlertContentActionNode in + return TextAlertContentActionNode(theme: theme, action: action) + } + + var actionVerticalSeparators: [ASDisplayNode] = [] + if actions.count > 1 { + for _ in 0 ..< actions.count - 1 { + let separatorNode = ASDisplayNode() + separatorNode.isLayerBacked = true + separatorNode.backgroundColor = theme.separatorColor + actionVerticalSeparators.append(separatorNode) + } + } + self.actionVerticalSeparators = actionVerticalSeparators + + super.init() + + if let titleNode = self.titleNode { + self.addSubnode(titleNode) + } + self.addSubnode(self.textNode) + + self.addSubnode(self.actionNodesSeparator) + + var i = 0 + for actionNode in self.actionNodes { + self.addSubnode(actionNode) + + let index = i + actionNode.highlightedUpdated = { [weak self] highlighted in + if highlighted { + self?.highlightedItemIndex = index + } + } + i += 1 + } + + for separatorNode in self.actionVerticalSeparators { + self.addSubnode(separatorNode) + } + } + + func setHighlightedItemIndex(_ index: Int?, update: Bool = false) { + self.highlightedItemIndex = index + + if update { + var i = 0 + for actionNode in self.actionNodes { + if i == index { + actionNode.setHighlighted(true, animated: false) + } else { + actionNode.setHighlighted(false, animated: false) + } + i += 1 + } + } + } + + override func decreaseHighlightedIndex() { + let currentHighlightedIndex = self.highlightedItemIndex ?? 0 + + self.setHighlightedItemIndex(max(0, currentHighlightedIndex - 1), update: true) + } + + override func increaseHighlightedIndex() { + let currentHighlightedIndex = self.highlightedItemIndex ?? -1 + + self.setHighlightedItemIndex(min(self.actionNodes.count - 1, currentHighlightedIndex + 1), update: true) + } + + override func performHighlightedAction() { + guard let highlightedItemIndex = self.highlightedItemIndex else { + return + } + + var i = 0 + for itemNode in self.actionNodes { + if i == highlightedItemIndex { + itemNode.performAction() + return + } + i += 1 + } + } + + override func updateTheme(_ theme: AlertControllerTheme) { + self.theme = theme + + if let titleNode = self.titleNode, let attributedText = titleNode.attributedText { + let updatedText = NSMutableAttributedString(attributedString: attributedText) + updatedText.addAttribute(NSAttributedString.Key.foregroundColor, value: theme.primaryColor, range: NSRange(location: 0, length: updatedText.length)) + titleNode.attributedText = updatedText + } + if let attributedText = self.textNode.attributedText { + let updatedText = NSMutableAttributedString(attributedString: attributedText) + updatedText.addAttribute(NSAttributedString.Key.foregroundColor, value: theme.primaryColor, range: NSRange(location: 0, length: updatedText.length)) + self.textNode.attributedText = updatedText + } + self.textNode.spoilerColor = theme.secondaryColor + + self.actionNodesSeparator.backgroundColor = theme.separatorColor + for actionNode in self.actionNodes { + actionNode.updateTheme(theme) + } + for separatorNode in self.actionVerticalSeparators { + separatorNode.backgroundColor = theme.separatorColor + } + + if let size = self.validLayout { + _ = self.updateLayout(size: size, transition: .immediate) + } + } + + override func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) -> CGSize { + self.validLayout = size + + let insets = UIEdgeInsets(top: 18.0, left: 18.0, bottom: 18.0, right: 18.0) + + var size = size + size.width = min(size.width, alertWidth) + + var titleSize: CGSize? + if let titleNode = self.titleNode { + titleSize = titleNode.updateLayout(CGSize(width: size.width - insets.left - insets.right, height: CGFloat.greatestFiniteMagnitude)) + } + let textSize = self.textNode.updateLayout(CGSize(width: size.width - insets.left - insets.right, height: CGFloat.greatestFiniteMagnitude)) + + let actionButtonHeight: CGFloat = 44.0 + + var minActionsWidth: CGFloat = 0.0 + let maxActionWidth: CGFloat = floor(size.width / CGFloat(self.actionNodes.count)) + let actionTitleInsets: CGFloat = 8.0 + + var effectiveActionLayout = self.actionLayout + for actionNode in self.actionNodes { + let actionTitleSize = actionNode.titleNode.updateLayout(CGSize(width: maxActionWidth, height: actionButtonHeight)) + if case .horizontal = effectiveActionLayout, actionTitleSize.height > actionButtonHeight * 0.6667 { + effectiveActionLayout = .vertical + } + switch effectiveActionLayout { + case .horizontal: + minActionsWidth += actionTitleSize.width + actionTitleInsets + case .vertical: + minActionsWidth = max(minActionsWidth, actionTitleSize.width + actionTitleInsets) + } + } + + let resultSize: CGSize + + var actionsHeight: CGFloat = 0.0 + switch effectiveActionLayout { + case .horizontal: + actionsHeight = actionButtonHeight + case .vertical: + actionsHeight = actionButtonHeight * CGFloat(self.actionNodes.count) + } + + let contentWidth = alertWidth - insets.left - insets.right + if let titleNode = self.titleNode, let titleSize = titleSize { + let spacing: CGFloat = 6.0 + let titleFrame = CGRect(origin: CGPoint(x: insets.left + floor((contentWidth - titleSize.width) / 2.0), y: insets.top), size: titleSize) + transition.updateFrame(node: titleNode, frame: titleFrame) + + let textFrame = CGRect(origin: CGPoint(x: insets.left + floor((contentWidth - textSize.width) / 2.0), y: titleFrame.maxY + spacing), size: textSize) + transition.updateFrame(node: self.textNode, frame: textFrame.offsetBy(dx: -1.0, dy: -1.0)) + + resultSize = CGSize(width: contentWidth + insets.left + insets.right, height: titleSize.height + spacing + textSize.height + actionsHeight + insets.top + insets.bottom) + } else { + let textFrame = CGRect(origin: CGPoint(x: insets.left + floor((contentWidth - textSize.width) / 2.0), y: insets.top), size: textSize) + transition.updateFrame(node: self.textNode, frame: textFrame) + + resultSize = CGSize(width: contentWidth + insets.left + insets.right, height: textSize.height + actionsHeight + insets.top + insets.bottom) + } + + self.actionNodesSeparator.frame = CGRect(origin: CGPoint(x: 0.0, y: resultSize.height - actionsHeight - UIScreenPixel), size: CGSize(width: resultSize.width, height: UIScreenPixel)) + + var actionOffset: CGFloat = 0.0 + let actionWidth: CGFloat = floor(resultSize.width / CGFloat(self.actionNodes.count)) + var separatorIndex = -1 + var nodeIndex = 0 + for actionNode in self.actionNodes { + if separatorIndex >= 0 { + let separatorNode = self.actionVerticalSeparators[separatorIndex] + switch effectiveActionLayout { + case .horizontal: + transition.updateFrame(node: separatorNode, frame: CGRect(origin: CGPoint(x: actionOffset - UIScreenPixel, y: resultSize.height - actionsHeight), size: CGSize(width: UIScreenPixel, height: actionsHeight - UIScreenPixel))) + case .vertical: + transition.updateFrame(node: separatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: resultSize.height - actionsHeight + actionOffset - UIScreenPixel), size: CGSize(width: resultSize.width, height: UIScreenPixel))) + } + } + separatorIndex += 1 + + let currentActionWidth: CGFloat + switch effectiveActionLayout { + case .horizontal: + if nodeIndex == self.actionNodes.count - 1 { + currentActionWidth = resultSize.width - actionOffset + } else { + currentActionWidth = actionWidth + } + case .vertical: + currentActionWidth = resultSize.width + } + + let actionNodeFrame: CGRect + switch effectiveActionLayout { + case .horizontal: + actionNodeFrame = CGRect(origin: CGPoint(x: actionOffset, y: resultSize.height - actionsHeight), size: CGSize(width: currentActionWidth, height: actionButtonHeight)) + actionOffset += currentActionWidth + case .vertical: + actionNodeFrame = CGRect(origin: CGPoint(x: 0.0, y: resultSize.height - actionsHeight + actionOffset), size: CGSize(width: currentActionWidth, height: actionButtonHeight)) + actionOffset += actionButtonHeight + } + + transition.updateFrame(node: actionNode, frame: actionNodeFrame) + + nodeIndex += 1 + } + + return resultSize + } +} + +public func textWithEntitiesAlertController(theme: AlertControllerTheme, title: NSAttributedString?, text: NSAttributedString, actions: [TextAlertAction], actionLayout: TextAlertContentActionLayout = .horizontal, allowInputInset: Bool = true, dismissAutomatically: Bool = true) -> AlertController { + var dismissImpl: (() -> Void)? + let controller = AlertController(theme: theme, contentNode: TextAlertWithEntitiesContentNode(theme: theme, title: title, text: text, actions: actions.map { action in + return TextAlertAction(type: action.type, title: action.title, action: { + if dismissAutomatically { + dismissImpl?() + } + action.action() + }) + }, actionLayout: actionLayout, dismissOnOutsideTap: true), allowInputInset: allowInputInset) + dismissImpl = { [weak controller] in + controller?.dismissAnimated() + } + + return controller +} + + +public func textWithEntitiesAlertController(alertContext: AlertControllerContext, title: NSAttributedString?, text: NSAttributedString, actions: [TextAlertAction], actionLayout: TextAlertContentActionLayout = .horizontal, allowInputInset: Bool = true, dismissAutomatically: Bool = true) -> AlertController { + let theme = alertContext.theme + + var dismissImpl: (() -> Void)? + let controller = AlertController(theme: theme, contentNode: TextAlertContentNode(theme: theme, title: title, text: text, actions: actions.map { action in + return TextAlertAction(type: action.type, title: action.title, action: { + if dismissAutomatically { + dismissImpl?() + } + action.action() + }) + }, actionLayout: actionLayout, dismissOnOutsideTap: true), allowInputInset: allowInputInset) + dismissImpl = { [weak controller] in + controller?.dismissAnimated() + } + + let presentationDataDisposable = alertContext.themeSignal.start(next: { [weak controller] theme in + controller?.theme = theme + }) + controller.dismissed = { _ in + presentationDataDisposable.dispose() + } + + return controller +} diff --git a/submodules/AlertUI/Sources/ThemedTextAlertController.swift b/submodules/AlertUI/Sources/ThemedTextAlertController.swift index fcc13819ae..c7ef5ddff0 100644 --- a/submodules/AlertUI/Sources/ThemedTextAlertController.swift +++ b/submodules/AlertUI/Sources/ThemedTextAlertController.swift @@ -1,5 +1,6 @@ import Foundation import UIKit +import AsyncDisplayKit import Display import SwiftSignalKit diff --git a/submodules/AuthorizationUI/BUILD b/submodules/AuthorizationUI/BUILD index e03bd64443..42b6200c8b 100644 --- a/submodules/AuthorizationUI/BUILD +++ b/submodules/AuthorizationUI/BUILD @@ -38,6 +38,8 @@ swift_library( "//submodules/InvisibleInkDustNode:InvisibleInkDustNode", "//submodules/AuthorizationUtils:AuthorizationUtils", "//submodules/ManagedAnimationNode:ManagedAnimationNode", + "//submodules/AlertUI:AlertUI", + "//submodules/TelegramUI/Components/TextNodeWithEntities:TextNodeWithEntities", ], visibility = [ "//visibility:public", diff --git a/submodules/AuthorizationUI/Sources/AuthorizationSequenceCodeEntryControllerNode.swift b/submodules/AuthorizationUI/Sources/AuthorizationSequenceCodeEntryControllerNode.swift index b06c675684..aecd5a27dc 100644 --- a/submodules/AuthorizationUI/Sources/AuthorizationSequenceCodeEntryControllerNode.swift +++ b/submodules/AuthorizationUI/Sources/AuthorizationSequenceCodeEntryControllerNode.swift @@ -12,9 +12,9 @@ import PhoneNumberFormat import AnimatedStickerNode import TelegramAnimatedStickerNode import SolidRoundedButtonNode -import InvisibleInkDustNode import AuthorizationUtils import TelegramStringFormatting +import TextNodeWithEntities final class AuthorizationSequenceCodeEntryControllerNode: ASDisplayNode, UITextFieldDelegate { private let strings: PresentationStrings @@ -24,9 +24,8 @@ final class AuthorizationSequenceCodeEntryControllerNode: ASDisplayNode, UITextF private let titleNode: ImmediateTextNode private let titleActivateAreaNode: AccessibilityAreaNode private let titleIconNode: ASImageNode - private let currentOptionNode: ImmediateTextNode + private let currentOptionNode: ImmediateTextNodeWithEntities private let currentOptionActivateAreaNode: AccessibilityAreaNode - private var dustNode: InvisibleInkDustNode? private let currentOptionInfoNode: ASTextNode private let currentOptionInfoActivateAreaNode: AccessibilityAreaNode @@ -105,11 +104,12 @@ final class AuthorizationSequenceCodeEntryControllerNode: ASDisplayNode, UITextF self.titleIconNode.displayWithoutProcessing = true self.titleIconNode.displaysAsynchronously = false - self.currentOptionNode = ImmediateTextNode() + self.currentOptionNode = ImmediateTextNodeWithEntities() self.currentOptionNode.isUserInteractionEnabled = false self.currentOptionNode.displaysAsynchronously = false self.currentOptionNode.lineSpacing = 0.1 self.currentOptionNode.maximumNumberOfLines = 0 + self.currentOptionNode.spoilerColor = self.theme.list.itemSecondaryTextColor self.currentOptionActivateAreaNode = AccessibilityAreaNode() self.currentOptionActivateAreaNode.accessibilityTraits = .staticText @@ -570,23 +570,6 @@ final class AuthorizationSequenceCodeEntryControllerNode: ASDisplayNode, UITextF 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 - additionalBottomInset)), items: items, transition: transition, failIfDoesNotFit: false) - if let textLayout = self.currentOptionNode.cachedLayout, !textLayout.spoilers.isEmpty { - if self.dustNode == nil { - let dustNode = InvisibleInkDustNode(textNode: nil, enableAnimations: true) - self.dustNode = dustNode - self.currentOptionNode.supernode?.insertSubnode(dustNode, aboveSubnode: self.currentOptionNode) - - } - if let dustNode = self.dustNode { - let textFrame = self.currentOptionNode.frame - dustNode.update(size: textFrame.size, color: self.theme.list.itemSecondaryTextColor, textColor: self.theme.list.itemPrimaryTextColor, rects: textLayout.spoilers.map { $0.1.offsetBy(dx: 3.0, dy: 3.0).insetBy(dx: 1.0, dy: 1.0) }, wordRects: textLayout.spoilerWords.map { $0.1.offsetBy(dx: 3.0, dy: 3.0).insetBy(dx: 1.0, dy: 1.0) }) - transition.updateFrame(node: dustNode, frame: textFrame.insetBy(dx: -3.0, dy: -3.0).offsetBy(dx: 0.0, dy: 3.0)) - } - } else if let dustNode = self.dustNode { - self.dustNode = nil - dustNode.removeFromSupernode() - } - self.nextOptionTitleNode.frame = self.nextOptionButtonNode.bounds self.titleActivateAreaNode.frame = self.titleNode.frame diff --git a/submodules/AuthorizationUI/Sources/AuthorizationSequenceController.swift b/submodules/AuthorizationUI/Sources/AuthorizationSequenceController.swift index 34a84c65fa..d144f13af0 100644 --- a/submodules/AuthorizationUI/Sources/AuthorizationSequenceController.swift +++ b/submodules/AuthorizationUI/Sources/AuthorizationSequenceController.swift @@ -18,6 +18,8 @@ import LegacyMediaPickerUI import PasswordSetupUI import TelegramNotices import AuthenticationServices +import Markdown +import AlertUI private enum InnerState: Equatable { case state(UnauthorizedAccountStateContents) @@ -280,7 +282,7 @@ public final class AuthorizationSequenceController: NavigationController, MFMail return controller } - private func codeEntryController(number: String, email: String?, type: SentAuthorizationCodeType, nextType: AuthorizationCodeNextType?, timeout: Int32?, termsOfService: (UnauthorizedAccountTermsOfService, Bool)?) -> AuthorizationSequenceCodeEntryController { + private func codeEntryController(number: String, phoneCodeHash: String, email: String?, type: SentAuthorizationCodeType, nextType: AuthorizationCodeNextType?, timeout: Int32?, termsOfService: (UnauthorizedAccountTermsOfService, Bool)?) -> AuthorizationSequenceCodeEntryController { var currentController: AuthorizationSequenceCodeEntryController? for c in self.viewControllers { if let c = c as? AuthorizationSequenceCodeEntryController { @@ -302,8 +304,57 @@ public final class AuthorizationSequenceController: NavigationController, MFMail let _ = TelegramEngineUnauthorized(account: strongSelf.account).auth.setState(state: UnauthorizedAccountState(isTestingEnvironment: strongSelf.account.testingEnvironment, masterDatacenterId: strongSelf.account.masterDatacenterId, contents: .phoneEntry(countryCode: countryCode, number: ""))).start() }) - controller.resetEmail = { - + controller.resetEmail = { [weak self, weak controller] in + if let self, case let .email(pattern, _, resetAvailablePeriod, resetPendingDate, _, setup) = type, !setup { + if let _ = resetPendingDate { + + } else if let resetAvailablePeriod { + let pattern = pattern.replacingOccurrences(of: "*", with: "#") + let title = NSAttributedString(string: self.presentationData.strings.Login_Email_ResetTitle, font: Font.semibold(self.presentationData.listsFontSize.baseDisplaySize), textColor: self.presentationData.theme.actionSheet.primaryTextColor) + let availableIn = unmuteIntervalString(strings: self.presentationData.strings, value: resetAvailablePeriod) + let body = MarkdownAttributeSet(font: Font.regular(self.presentationData.listsFontSize.baseDisplaySize * 13.0 / 17.0), textColor: self.presentationData.theme.actionSheet.primaryTextColor) + let bold = MarkdownAttributeSet(font: Font.semibold(self.presentationData.listsFontSize.baseDisplaySize * 13.0 / 17.0), textColor: self.presentationData.theme.actionSheet.primaryTextColor) + let text = parseMarkdownIntoAttributedString(self.presentationData.strings.Login_Email_ResetText(pattern, availableIn).string, attributes: MarkdownAttributes(body: body, bold: bold, link: body, linkAttribute: { _ in nil }), textAlignment: .center).mutableCopy() as! NSMutableAttributedString + if let regex = try? NSRegularExpression(pattern: "\\#", options: []) { + let matches = regex.matches(in: text.string, options: [], range: NSMakeRange(0, text.length)) + if let first = matches.first { + text.addAttribute(NSAttributedString.Key(rawValue: TelegramTextAttributes.Spoiler), value: true, range: NSRange(location: first.range.location, length: matches.count)) + } + } + + let alertController = textWithEntitiesAlertController(theme: AlertControllerTheme(presentationData: self.presentationData), title: title, text: text, actions: [TextAlertAction(type: .genericAction, title: self.presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .defaultAction, title: self.presentationData.strings.Login_Email_Reset, action: { [weak self] in + guard let self else { + return + } + self.actionDisposable.set( + (resetLoginEmail(account: self.account, phoneNumber: number, phoneCodeHash: phoneCodeHash) + |> deliverOnMainQueue).start(error: { [weak self] error in + Queue.mainQueue().async { + guard let self, let controller = controller else { + return + } + controller.inProgress = false + + let text: String + switch error { + case .limitExceeded: + text = self.presentationData.strings.Login_CodeFloodError + case .generic: + text = self.presentationData.strings.Login_UnknownError + case .codeExpired: + text = self.presentationData.strings.Login_CodeExpired + let account = self.account + let _ = TelegramEngineUnauthorized(account: self.account).auth.setState(state: UnauthorizedAccountState(isTestingEnvironment: account.testingEnvironment, masterDatacenterId: account.masterDatacenterId, contents: .empty)).start() + } + + controller.presentInGlobalOverlay(standardTextAlertController(theme: AlertControllerTheme(presentationData: self.presentationData), title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: self.presentationData.strings.Common_OK, action: {})])) + } + }) + ) + })]) + controller?.present(alertController, in: .window(.root)) + } + } } controller.loginWithCode = { [weak self, weak controller] code in if let strongSelf = self { @@ -1068,7 +1119,7 @@ public final class AuthorizationSequenceController: NavigationController, MFMail controllers.append(self.phoneEntryController(countryCode: countryCode, number: number, splashController: previousSplashController)) self.setViewControllers(controllers, animated: !self.viewControllers.isEmpty && (previousSplashController == nil || self.viewControllers.count > 2)) - case let .confirmationCodeEntry(number, type, _, timeout, nextType, _): + case let .confirmationCodeEntry(number, type, phoneCodeHash, timeout, nextType, _): var controllers: [ViewController] = [] if !self.otherAccountPhoneNumbers.1.isEmpty { controllers.append(self.splashController()) @@ -1081,7 +1132,7 @@ public final class AuthorizationSequenceController: NavigationController, MFMail if let _ = self.currentEmail { controllers.append(self.emailSetupController(number: number, appleSignInAllowed: self.appleSignInAllowed)) } - controllers.append(self.codeEntryController(number: number, email: self.currentEmail, type: type, nextType: nextType, timeout: timeout, termsOfService: nil)) + controllers.append(self.codeEntryController(number: number, phoneCodeHash: phoneCodeHash, email: self.currentEmail, type: type, nextType: nextType, timeout: timeout, termsOfService: nil)) } self.setViewControllers(controllers, animated: !self.viewControllers.isEmpty) case let .passwordEntry(hint, _, _, suggestReset, syncContacts): diff --git a/submodules/AuthorizationUtils/Sources/AuthorizationOptionText.swift b/submodules/AuthorizationUtils/Sources/AuthorizationOptionText.swift index 48308e3d26..dc26d51911 100644 --- a/submodules/AuthorizationUtils/Sources/AuthorizationOptionText.swift +++ b/submodules/AuthorizationUtils/Sources/AuthorizationOptionText.swift @@ -29,12 +29,8 @@ public func authorizationCurrentOptionText(_ type: SentAuthorizationCodeType, ph return NSAttributedString(string: "", font: Font.regular(fontSize), textColor: primaryColor, paragraphAlignment: .center) case let .email(emailPattern, _, _, _, _, _): let mutableString = NSAttributedString(string: strings.Login_EnterCodeEmailText(email ?? emailPattern).string, font: Font.regular(fontSize), textColor: primaryColor, paragraphAlignment: .center).mutableCopy() as! NSMutableAttributedString - - let string = mutableString.string - let nsString = string as NSString - if let regex = try? NSRegularExpression(pattern: "\\*", options: []) { - let matches = regex.matches(in: string, options: [], range: NSMakeRange(0, nsString.length)) + let matches = regex.matches(in: mutableString.string, options: [], range: NSMakeRange(0, mutableString.length)) if let first = matches.first { mutableString.addAttribute(NSAttributedString.Key(rawValue: TelegramTextAttributes.Spoiler), value: true, range: NSRange(location: first.range.location, length: matches.count)) } diff --git a/submodules/Display/Source/TextAlertController.swift b/submodules/Display/Source/TextAlertController.swift index 28b339166e..54437bb0f6 100644 --- a/submodules/Display/Source/TextAlertController.swift +++ b/submodules/Display/Source/TextAlertController.swift @@ -29,7 +29,7 @@ public final class TextAlertContentActionNode: HighlightableButtonNode { private let backgroundNode: ASDisplayNode - var highlightedUpdated: (Bool) -> Void = { _ in } + public var highlightedUpdated: (Bool) -> Void = { _ in } public init(theme: AlertControllerTheme, action: TextAlertAction) { self.theme = theme @@ -68,13 +68,13 @@ public final class TextAlertContentActionNode: HighlightableButtonNode { }) } - func performAction() { + public func performAction() { if self.actionEnabled { self.action.action() } } - func setHighlighted(_ highlighted: Bool, animated: Bool) { + public func setHighlighted(_ highlighted: Bool, animated: Bool) { self.highlightedUpdated(highlighted) if highlighted { if self.backgroundNode.supernode == nil { diff --git a/submodules/PeerInfoUI/Sources/ChannelAdminController.swift b/submodules/PeerInfoUI/Sources/ChannelAdminController.swift index 80bc21a037..f0fc00b5b7 100644 --- a/submodules/PeerInfoUI/Sources/ChannelAdminController.swift +++ b/submodules/PeerInfoUI/Sources/ChannelAdminController.swift @@ -1406,14 +1406,14 @@ public func channelAdminController(context: AccountContext, updatedPresentationD footerItem = ChannelAdminAddBotFooterItem(theme: presentationData.theme, title: state.adminRights ? presentationData.strings.Bot_AddToChat_Add_AddAsAdmin : presentationData.strings.Bot_AddToChat_Add_AddAsMember, action: { if state.adminRights { let theme = AlertControllerTheme(presentationData: presentationData) - let attributedTitle = NSAttributedString(string: presentationData.strings.Bot_AddToChat_Add_AdminAlertTitle, font: Font.medium(17.0), textColor: theme.primaryColor, paragraphAlignment: .center) + let attributedTitle = NSAttributedString(string: presentationData.strings.Bot_AddToChat_Add_AdminAlertTitle, font: Font.semibold(presentationData.listsFontSize.baseDisplaySize), textColor: theme.primaryColor, paragraphAlignment: .center) let text = isGroup ? presentationData.strings.Bot_AddToChat_Add_AdminAlertTextGroup(peerTitle).string : presentationData.strings.Bot_AddToChat_Add_AdminAlertTextChannel(peerTitle).string - let body = MarkdownAttributeSet(font: Font.regular(13.0), textColor: theme.primaryColor) - let bold = MarkdownAttributeSet(font: Font.semibold(13.0), textColor: theme.primaryColor) + let body = MarkdownAttributeSet(font: Font.regular(presentationData.listsFontSize.baseDisplaySize * 13.0 / 17.0), textColor: theme.primaryColor) + let bold = MarkdownAttributeSet(font: Font.semibold(presentationData.listsFontSize.baseDisplaySize * 13.0 / 17.0), textColor: theme.primaryColor) let attributedText = parseMarkdownIntoAttributedString(text, attributes: MarkdownAttributes(body: body, bold: bold, link: body, linkAttribute: { _ in return nil }), textAlignment: .center) - + let controller = richTextAlertController(context: context, title: attributedTitle, text: attributedText, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Bot_AddToChat_Add_AdminAlertAdd, action: { rightButtonActionImpl() }), TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: { diff --git a/submodules/PeerInfoUI/Sources/ChannelOwnershipTransferController.swift b/submodules/PeerInfoUI/Sources/ChannelOwnershipTransferController.swift index ab95da6445..db0e459c4d 100644 --- a/submodules/PeerInfoUI/Sources/ChannelOwnershipTransferController.swift +++ b/submodules/PeerInfoUI/Sources/ChannelOwnershipTransferController.swift @@ -559,9 +559,9 @@ private func confirmChannelOwnershipTransferController(context: AccountContext, text = presentationData.strings.Channel_OwnershipTransfer_DescriptionInfo(EnginePeer(peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), EnginePeer(member).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)).string } - let attributedTitle = NSAttributedString(string: title, font: Font.medium(17.0), textColor: theme.primaryColor, paragraphAlignment: .center) - let body = MarkdownAttributeSet(font: Font.regular(13.0), textColor: theme.primaryColor) - let bold = MarkdownAttributeSet(font: Font.semibold(13.0), textColor: theme.primaryColor) + let attributedTitle = NSAttributedString(string: title, font: Font.semibold(presentationData.listsFontSize.baseDisplaySize), textColor: theme.primaryColor, paragraphAlignment: .center) + let body = MarkdownAttributeSet(font: Font.regular(presentationData.listsFontSize.baseDisplaySize * 13.0 / 17.0), textColor: theme.primaryColor) + let bold = MarkdownAttributeSet(font: Font.semibold(presentationData.listsFontSize.baseDisplaySize * 13.0 / 17.0), textColor: theme.primaryColor) let attributedText = parseMarkdownIntoAttributedString(text, attributes: MarkdownAttributes(body: body, bold: bold, link: body, linkAttribute: { _ in return nil }), textAlignment: .center) let controller = richTextAlertController(context: context, title: attributedTitle, text: attributedText, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Channel_OwnershipTransfer_ChangeOwner, action: { @@ -575,16 +575,17 @@ func channelOwnershipTransferController(context: AccountContext, updatedPresenta let presentationData = updatedPresentationData?.initial ?? context.sharedContext.currentPresentationData.with { $0 } let theme = AlertControllerTheme(presentationData: presentationData) - var title: NSAttributedString? = NSAttributedString(string: presentationData.strings.OwnershipTransfer_SecurityCheck, font: Font.medium(presentationData.listsFontSize.itemListBaseFontSize), textColor: theme.primaryColor, paragraphAlignment: .center) + var title: NSAttributedString? = NSAttributedString(string: presentationData.strings.OwnershipTransfer_SecurityCheck, font: Font.semibold(presentationData.listsFontSize.itemListBaseFontSize), textColor: theme.primaryColor, paragraphAlignment: .center) var text = presentationData.strings.OwnershipTransfer_SecurityRequirements + let textFontSize = presentationData.listsFontSize.baseDisplaySize * 13.0 / 17.0 + var isGroup = true if let channel = peer as? TelegramChannel, case .broadcast = channel.info { isGroup = false } var actions: [TextAlertAction] = [] - switch initialError { case .requestPassword: return confirmChannelOwnershipTransferController(context: context, updatedPresentationData: updatedPresentationData, peer: peer, member: member, present: present, completion: completion) @@ -618,8 +619,8 @@ func channelOwnershipTransferController(context: AccountContext, updatedPresenta actions = [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})] } - let body = MarkdownAttributeSet(font: Font.regular(13.0), textColor: theme.primaryColor) - let bold = MarkdownAttributeSet(font: Font.semibold(13.0), textColor: theme.primaryColor) + let body = MarkdownAttributeSet(font: Font.regular(textFontSize), textColor: theme.primaryColor) + let bold = MarkdownAttributeSet(font: Font.semibold(textFontSize), textColor: theme.primaryColor) let attributedText = parseMarkdownIntoAttributedString(text, attributes: MarkdownAttributes(body: body, bold: bold, link: body, linkAttribute: { _ in return nil }), textAlignment: .center) return richTextAlertController(context: context, title: title, text: attributedText, actions: actions) diff --git a/submodules/PeerInfoUI/Sources/ChannelPermissionsController.swift b/submodules/PeerInfoUI/Sources/ChannelPermissionsController.swift index 05415756a0..6031dda89c 100644 --- a/submodules/PeerInfoUI/Sources/ChannelPermissionsController.swift +++ b/submodules/PeerInfoUI/Sources/ChannelPermissionsController.swift @@ -966,9 +966,9 @@ public func channelPermissionsController(context: AccountContext, updatedPresent controller.navigationPresentation = .modal controller.setState(.custom(icon: .animation("BroadcastGroup"), title: presentationData.strings.BroadcastGroups_IntroTitle, subtitle: nil, text: presentationData.strings.BroadcastGroups_IntroText, buttonTitle: presentationData.strings.BroadcastGroups_Convert, secondaryButtonTitle: presentationData.strings.BroadcastGroups_Cancel, footerText: nil), animated: false) controller.proceed = { [weak controller] result in - let attributedTitle = NSAttributedString(string: presentationData.strings.BroadcastGroups_ConfirmationAlert_Title, font: Font.medium(17.0), textColor: presentationData.theme.actionSheet.primaryTextColor, paragraphAlignment: .center) - let body = MarkdownAttributeSet(font: Font.regular(13.0), textColor: presentationData.theme.actionSheet.primaryTextColor) - let bold = MarkdownAttributeSet(font: Font.semibold(13.0), textColor: presentationData.theme.actionSheet.primaryTextColor) + let attributedTitle = NSAttributedString(string: presentationData.strings.BroadcastGroups_ConfirmationAlert_Title, font: Font.semibold(presentationData.listsFontSize.baseDisplaySize), textColor: presentationData.theme.actionSheet.primaryTextColor, paragraphAlignment: .center) + let body = MarkdownAttributeSet(font: Font.regular(presentationData.listsFontSize.baseDisplaySize * 13.0 / 17.0), textColor: presentationData.theme.actionSheet.primaryTextColor) + let bold = MarkdownAttributeSet(font: Font.semibold(presentationData.listsFontSize.baseDisplaySize * 13.0 / 17.0), textColor: presentationData.theme.actionSheet.primaryTextColor) let attributedText = parseMarkdownIntoAttributedString(presentationData.strings.BroadcastGroups_ConfirmationAlert_Text, attributes: MarkdownAttributes(body: body, bold: bold, link: body, linkAttribute: { _ in return nil }), textAlignment: .center) let alertController = richTextAlertController(context: context, title: attributedTitle, text: attributedText, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .defaultAction, title: presentationData.strings.BroadcastGroups_ConfirmationAlert_Convert, action: { [weak controller] in diff --git a/submodules/PresentationDataUtils/Sources/AlertTheme.swift b/submodules/PresentationDataUtils/Sources/AlertTheme.swift index 8de1164e1c..610480dfc7 100644 --- a/submodules/PresentationDataUtils/Sources/AlertTheme.swift +++ b/submodules/PresentationDataUtils/Sources/AlertTheme.swift @@ -31,3 +31,19 @@ public func textAlertController(sharedContext: SharedAccountContext, title: Stri public func richTextAlertController(context: AccountContext, title: NSAttributedString?, text: NSAttributedString, actions: [TextAlertAction], actionLayout: TextAlertContentActionLayout = .horizontal, allowInputInset: Bool = true, dismissAutomatically: Bool = true) -> AlertController { return richTextAlertController(alertContext: AlertControllerContext(theme: AlertControllerTheme(presentationData: context.sharedContext.currentPresentationData.with { $0 }), themeSignal: context.sharedContext.presentationData |> map { presentationData in AlertControllerTheme(presentationData: presentationData) }), title: title, text: text, actions: actions, actionLayout: actionLayout, allowInputInset: allowInputInset, dismissAutomatically: dismissAutomatically) } + +public func textWithEntitiesAlertController(context: AccountContext, title: NSAttributedString?, text: NSAttributedString, actions: [TextAlertAction], actionLayout: TextAlertContentActionLayout = .horizontal, allowInputInset: Bool = true, dismissAutomatically: Bool = true) -> AlertController { + return textWithEntitiesAlertController( + alertContext: AlertControllerContext( + theme: AlertControllerTheme(presentationData: context.sharedContext.currentPresentationData.with { $0 }), + themeSignal: context.sharedContext.presentationData |> map { presentationData in AlertControllerTheme(presentationData: presentationData) } + ), + title: title, + text: text, + actions: actions, + actionLayout: actionLayout, + allowInputInset: allowInputInset, + dismissAutomatically: dismissAutomatically + ) +} + diff --git a/submodules/TelegramCore/Sources/Authorization.swift b/submodules/TelegramCore/Sources/Authorization.swift index 6f63544a07..9b49ad9ab5 100644 --- a/submodules/TelegramCore/Sources/Authorization.swift +++ b/submodules/TelegramCore/Sources/Authorization.swift @@ -805,6 +805,62 @@ public func verifyLoginEmailSetup(account: UnauthorizedAccount, code: Authorizat |> ignoreValues } +public enum AuthorizationEmailResetError { + case generic + case limitExceeded + case codeExpired +} + +public func resetLoginEmail(account: UnauthorizedAccount, phoneNumber: String, phoneCodeHash: String) -> Signal { + return account.postbox.transaction { transaction -> Signal in + if let state = transaction.getState() as? UnauthorizedAccountState { + switch state.contents { + case let .confirmationCodeEntry(phoneNumber, _, phoneCodeHash, _, _, syncContacts): + return account.network.request(Api.functions.auth.resetLoginEmail(phoneNumber: phoneNumber, phoneCodeHash: phoneCodeHash), automaticFloodWait: false) + |> `catch` { error -> Signal in + let errorDescription = error.errorDescription ?? "" + if errorDescription.hasPrefix("FLOOD_WAIT") { + return .fail(.limitExceeded) + } else if errorDescription == "CODE_HASH_EXPIRED" || errorDescription == "PHONE_CODE_EXPIRED" { + return .fail(.codeExpired) + } else { + return .fail(.generic) + } + } + |> mapToSignal { sentCode -> Signal in + return account.postbox.transaction { transaction -> Signal in + switch sentCode { + case let .sentCode(_, type, phoneCodeHash, nextType, codeTimeout): + var parsedNextType: AuthorizationCodeNextType? + if let nextType = nextType { + parsedNextType = AuthorizationCodeNextType(apiType: nextType) + } + + transaction.setState(UnauthorizedAccountState(isTestingEnvironment: account.testingEnvironment, masterDatacenterId: account.masterDatacenterId, contents: .confirmationCodeEntry(number: phoneNumber, type: SentAuthorizationCodeType(apiType: type), hash: phoneCodeHash, timeout: codeTimeout, nextType: parsedNextType, syncContacts: syncContacts))) + + return .complete() + case .sentCodeSuccess: + return .complete() + } + } + |> switchToLatest + |> mapError { _ -> AuthorizationEmailResetError in + } + |> ignoreValues + } + default: + return .fail(.generic) + } + } else { + return .fail(.generic) + } + } + |> mapError { _ -> AuthorizationEmailResetError in + } + |> switchToLatest + |> ignoreValues +} + public func authorizeWithCode(accountManager: AccountManager, account: UnauthorizedAccount, code: AuthorizationCode, termsOfService: UnauthorizedAccountTermsOfService?, forcedPasswordSetupNotice: @escaping (Int32) -> (NoticeEntryKey, CodableEntry)?) -> Signal { return account.postbox.transaction { transaction -> Signal in if let state = transaction.getState() as? UnauthorizedAccountState { diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index 5a9cacb82d..fe5bbd260f 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -4289,30 +4289,30 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G if let botAdminRights { if botAdminRights.rights.isEmpty { let stringWithRanges = strongSelf.presentationData.strings.RequestPeer_SelectionConfirmationInviteAdminText(botName, peerName) - let formattedString = NSMutableAttributedString(string: stringWithRanges.string, font: Font.regular(13.0), textColor: theme.primaryColor, paragraphAlignment: .center) + let formattedString = NSMutableAttributedString(string: stringWithRanges.string, font: Font.regular(strongSelf.presentationData.listsFontSize.baseDisplaySize * 13.0 / 17.0), textColor: theme.primaryColor, paragraphAlignment: .center) for range in stringWithRanges.ranges.prefix(2) { - formattedString.addAttribute(.font, value: Font.semibold(13.0), range: range.range) + formattedString.addAttribute(.font, value: Font.semibold(strongSelf.presentationData.listsFontSize.baseDisplaySize * 13.0 / 17.0), range: range.range) } attributedText = formattedString } else { let stringWithRanges = strongSelf.presentationData.strings.RequestPeer_SelectionConfirmationInviteWithRightsText(botName, peerName, stringForAdminRights(strings: strongSelf.presentationData.strings, adminRights: botAdminRights, isChannel: isChannel)) - let formattedString = NSMutableAttributedString(string: stringWithRanges.string, font: Font.regular(13.0), textColor: theme.primaryColor, paragraphAlignment: .center) + let formattedString = NSMutableAttributedString(string: stringWithRanges.string, font: Font.regular(strongSelf.presentationData.listsFontSize.baseDisplaySize * 13.0 / 17.0), textColor: theme.primaryColor, paragraphAlignment: .center) for range in stringWithRanges.ranges.prefix(2) { - formattedString.addAttribute(.font, value: Font.semibold(13.0), range: range.range) + formattedString.addAttribute(.font, value: Font.semibold(strongSelf.presentationData.listsFontSize.baseDisplaySize * 13.0 / 17.0), range: range.range) } attributedText = formattedString } } else { if case let .group(group) = peerType, group.botParticipant { let stringWithRanges = strongSelf.presentationData.strings.RequestPeer_SelectionConfirmationInviteText(botName, peerName) - let formattedString = NSMutableAttributedString(string: stringWithRanges.string, font: Font.regular(13.0), textColor: theme.primaryColor, paragraphAlignment: .center) + let formattedString = NSMutableAttributedString(string: stringWithRanges.string, font: Font.regular(strongSelf.presentationData.listsFontSize.baseDisplaySize * 13.0 / 17.0), textColor: theme.primaryColor, paragraphAlignment: .center) for range in stringWithRanges.ranges.prefix(2) { - formattedString.addAttribute(.font, value: Font.semibold(13.0), range: range.range) + formattedString.addAttribute(.font, value: Font.semibold(strongSelf.presentationData.listsFontSize.baseDisplaySize * 13.0 / 17.0), range: range.range) } attributedText = formattedString } else { attributedTitle = nil - attributedText = NSAttributedString(string: strongSelf.presentationData.strings.RequestPeer_SelectionConfirmationTitle(peerName, botName).string, font: Font.medium(17.0), textColor: theme.primaryColor, paragraphAlignment: .center) + attributedText = NSAttributedString(string: strongSelf.presentationData.strings.RequestPeer_SelectionConfirmationTitle(peerName, botName).string, font: Font.semibold(strongSelf.presentationData.listsFontSize.baseDisplaySize), textColor: theme.primaryColor, paragraphAlignment: .center) } } } @@ -11085,9 +11085,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G if values.contains(.convertToGigagroup) && !strongSelf.displayedConvertToGigagroupSuggestion { strongSelf.displayedConvertToGigagroupSuggestion = true - let attributedTitle = NSAttributedString(string: strongSelf.presentationData.strings.BroadcastGroups_LimitAlert_Title, font: Font.medium(17.0), textColor: strongSelf.presentationData.theme.actionSheet.primaryTextColor, paragraphAlignment: .center) - let body = MarkdownAttributeSet(font: Font.regular(13.0), textColor: strongSelf.presentationData.theme.actionSheet.primaryTextColor) - let bold = MarkdownAttributeSet(font: Font.semibold(13.0), textColor: strongSelf.presentationData.theme.actionSheet.primaryTextColor) + let attributedTitle = NSAttributedString(string: strongSelf.presentationData.strings.BroadcastGroups_LimitAlert_Title, font: Font.semibold(strongSelf.presentationData.listsFontSize.baseDisplaySize), textColor: strongSelf.presentationData.theme.actionSheet.primaryTextColor, paragraphAlignment: .center) + let body = MarkdownAttributeSet(font: Font.regular(strongSelf.presentationData.listsFontSize.baseDisplaySize * 13.0 / 17.0), textColor: strongSelf.presentationData.theme.actionSheet.primaryTextColor) + let bold = MarkdownAttributeSet(font: Font.semibold(strongSelf.presentationData.listsFontSize.baseDisplaySize * 13.0 / 17.0), textColor: strongSelf.presentationData.theme.actionSheet.primaryTextColor) let participantsLimit = strongSelf.context.currentLimitsConfiguration.with { $0 }.maxSupergroupMemberCount let text = strongSelf.presentationData.strings.BroadcastGroups_LimitAlert_Text(presentationStringsFormattedNumber(participantsLimit, strongSelf.presentationData.dateTimeFormat.groupingSeparator)).string @@ -11103,9 +11103,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G controller.navigationPresentation = .modal controller.setState(.custom(icon: .animation("BroadcastGroup"), title: presentationData.strings.BroadcastGroups_IntroTitle, subtitle: nil, text: presentationData.strings.BroadcastGroups_IntroText, buttonTitle: presentationData.strings.BroadcastGroups_Convert, secondaryButtonTitle: presentationData.strings.BroadcastGroups_Cancel, footerText: nil), animated: false) controller.proceed = { [weak controller] result in - let attributedTitle = NSAttributedString(string: presentationData.strings.BroadcastGroups_ConfirmationAlert_Title, font: Font.medium(17.0), textColor: presentationData.theme.actionSheet.primaryTextColor, paragraphAlignment: .center) - let body = MarkdownAttributeSet(font: Font.regular(13.0), textColor: presentationData.theme.actionSheet.primaryTextColor) - let bold = MarkdownAttributeSet(font: Font.semibold(13.0), textColor: presentationData.theme.actionSheet.primaryTextColor) + let attributedTitle = NSAttributedString(string: presentationData.strings.BroadcastGroups_ConfirmationAlert_Title, font: Font.semibold(presentationData.listsFontSize.baseDisplaySize), textColor: presentationData.theme.actionSheet.primaryTextColor, paragraphAlignment: .center) + let body = MarkdownAttributeSet(font: Font.regular(presentationData.listsFontSize.baseDisplaySize * 13.0 / 17.0), textColor: presentationData.theme.actionSheet.primaryTextColor) + let bold = MarkdownAttributeSet(font: Font.semibold(presentationData.listsFontSize.baseDisplaySize * 13.0 / 17.0), textColor: presentationData.theme.actionSheet.primaryTextColor) let attributedText = parseMarkdownIntoAttributedString(presentationData.strings.BroadcastGroups_ConfirmationAlert_Text, attributes: MarkdownAttributes(body: body, bold: bold, link: body, linkAttribute: { _ in return nil }), textAlignment: .center) let alertController = richTextAlertController(context: context, title: attributedTitle, text: attributedText, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: { diff --git a/submodules/TelegramUI/Sources/OpenResolvedUrl.swift b/submodules/TelegramUI/Sources/OpenResolvedUrl.swift index 1de8c2e2d4..a99bc539a8 100644 --- a/submodules/TelegramUI/Sources/OpenResolvedUrl.swift +++ b/submodules/TelegramUI/Sources/OpenResolvedUrl.swift @@ -79,7 +79,7 @@ func openResolvedUrlImpl(_ resolvedUrl: ResolvedUrl, context: AccountContext, ur let addMemberImpl = { let presentationData = context.sharedContext.currentPresentationData.with { $0 } let theme = AlertControllerTheme(presentationData: presentationData) - let attributedTitle = NSAttributedString(string: presentationData.strings.Bot_AddToChat_Add_MemberAlertTitle, font: Font.medium(17.0), textColor: theme.primaryColor, paragraphAlignment: .center) + let attributedTitle = NSAttributedString(string: presentationData.strings.Bot_AddToChat_Add_MemberAlertTitle, font: Font.semibold(presentationData.listsFontSize.baseDisplaySize), textColor: theme.primaryColor, paragraphAlignment: .center) var isGroup: Bool = false var peerTitle: String = "" @@ -95,8 +95,8 @@ func openResolvedUrlImpl(_ resolvedUrl: ResolvedUrl, context: AccountContext, ur let text = isGroup ? presentationData.strings.Bot_AddToChat_Add_MemberAlertTextGroup(peerTitle).string : presentationData.strings.Bot_AddToChat_Add_MemberAlertTextChannel(peerTitle).string - let body = MarkdownAttributeSet(font: Font.regular(13.0), textColor: theme.primaryColor) - let bold = MarkdownAttributeSet(font: Font.semibold(13.0), textColor: theme.primaryColor) + let body = MarkdownAttributeSet(font: Font.regular(presentationData.listsFontSize.baseDisplaySize * 13.0 / 17.0), textColor: theme.primaryColor) + let bold = MarkdownAttributeSet(font: Font.semibold(presentationData.listsFontSize.baseDisplaySize * 13.0 / 17.0), textColor: theme.primaryColor) let attributedText = parseMarkdownIntoAttributedString(text, attributes: MarkdownAttributes(body: body, bold: bold, link: body, linkAttribute: { _ in return nil }), textAlignment: .center) let controller = richTextAlertController(context: context, title: attributedTitle, text: attributedText, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Bot_AddToChat_Add_MemberAlertAdd, action: { diff --git a/submodules/TelegramUI/Sources/OwnershipTransferController.swift b/submodules/TelegramUI/Sources/OwnershipTransferController.swift index 24cd7beec7..10ff585ed3 100644 --- a/submodules/TelegramUI/Sources/OwnershipTransferController.swift +++ b/submodules/TelegramUI/Sources/OwnershipTransferController.swift @@ -84,11 +84,11 @@ func ownershipTransferController(context: AccountContext, updatedPresentationDat let presentationData = updatedPresentationData?.initial ?? context.sharedContext.currentPresentationData.with { $0 } let theme = AlertControllerTheme(presentationData: presentationData) - var title: NSAttributedString? = NSAttributedString(string: presentationData.strings.OwnershipTransfer_SecurityCheck, font: Font.medium(presentationData.listsFontSize.itemListBaseFontSize), textColor: theme.primaryColor, paragraphAlignment: .center) + var title: NSAttributedString? = NSAttributedString(string: presentationData.strings.OwnershipTransfer_SecurityCheck, font: Font.semibold(presentationData.listsFontSize.itemListBaseFontSize), textColor: theme.primaryColor, paragraphAlignment: .center) var text = presentationData.strings.OwnershipTransfer_SecurityRequirements var actions: [TextAlertAction] = [] - + let textFontSize = presentationData.listsFontSize.baseDisplaySize * 13.0 / 17.0 switch initialError { case .requestPassword: return commitOwnershipTransferController(context: context, updatedPresentationData: updatedPresentationData, present: present, commit: commit, completion: completion) @@ -114,8 +114,8 @@ func ownershipTransferController(context: AccountContext, updatedPresentationDat actions = [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})] } - let body = MarkdownAttributeSet(font: Font.regular(13.0), textColor: theme.primaryColor) - let bold = MarkdownAttributeSet(font: Font.semibold(13.0), textColor: theme.primaryColor) + let body = MarkdownAttributeSet(font: Font.regular(textFontSize), textColor: theme.primaryColor) + let bold = MarkdownAttributeSet(font: Font.semibold(textFontSize), textColor: theme.primaryColor) let attributedText = parseMarkdownIntoAttributedString(text, attributes: MarkdownAttributes(body: body, bold: bold, link: body, linkAttribute: { _ in return nil }), textAlignment: .center) return richTextAlertController(context: context, title: title, text: attributedText, actions: actions)