diff --git a/TelegramUI/AvatarNode.swift b/TelegramUI/AvatarNode.swift index c5071a13c3..d69987481c 100644 --- a/TelegramUI/AvatarNode.swift +++ b/TelegramUI/AvatarNode.swift @@ -90,6 +90,46 @@ public enum AvatarNodeColorOverride { case blue } +public final class AvatarEditOverlayNode: ASDisplayNode { + + override public init() { + super.init() + + self.isOpaque = false + self.displaysAsynchronously = true + } + + @objc override public class func draw(_ bounds: CGRect, withParameters parameters: Any?, isCancelled: () -> Bool, isRasterizing: Bool) { + assertNotOnMainThread() + + let context = UIGraphicsGetCurrentContext()! + + if !isRasterizing { + context.setBlendMode(.copy) + context.setFillColor(UIColor.clear.cgColor) + context.fill(bounds) + } + + context.beginPath() + context.addEllipse(in: CGRect(x: 0.0, y: 0.0, width: bounds.size.width, height: + bounds.size.height)) + context.clip() + + context.setFillColor(UIColor(rgb: 0x000000, alpha: 0.4).cgColor) + context.fill(bounds) + + context.translateBy(x: bounds.size.width / 2.0, y: bounds.size.height / 2.0) + context.scaleBy(x: 1.0, y: -1.0) + context.translateBy(x: -bounds.size.width / 2.0, y: -bounds.size.height / 2.0) + + context.setBlendMode(.normal) + + if let editAvatarIcon = generateTintedImage(image: UIImage(bundleImageName: "Avatar/EditAvatarIcon"), color: .white) { + context.draw(editAvatarIcon.cgImage!, in: CGRect(origin: CGPoint(x: floor((bounds.size.width - editAvatarIcon.size.width) / 2.0), y: floor((bounds.size.height - editAvatarIcon.size.height) / 2.0)), size: editAvatarIcon.size)) + } + } +} + public final class AvatarNode: ASDisplayNode { var font: UIFont { didSet { @@ -107,6 +147,7 @@ public final class AvatarNode: ASDisplayNode { private var parameters: AvatarNodeParameters? private var theme: PresentationTheme? let imageNode: ImageNode + var editOverlayNode: AvatarEditOverlayNode? private let imageReadyDisposable = MetaDisposable() private var state: AvatarNodeState = .empty @@ -143,8 +184,10 @@ public final class AvatarNode: ASDisplayNode { let updateImage = !value.size.equalTo(super.frame.size) super.frame = value self.imageNode.frame = CGRect(origin: CGPoint(), size: value.size) + self.editOverlayNode?.frame = self.imageNode.frame if updateImage && !self.displaySuspended { self.setNeedsDisplay() + self.editOverlayNode?.setNeedsDisplay() } } } @@ -177,11 +220,24 @@ public final class AvatarNode: ASDisplayNode { self.displaySuspended = true self.contents = nil + let theme = account.telegramApplicationContext.currentPresentationData.with { $0 }.theme + if let signal = peerAvatarImage(account: account, peer: peer, authorOfMessage: authorOfMessage, representation: representation) { self.imageReady.set(self.imageNode.ready) self.imageNode.setSignal(signal) - parameters = AvatarNodeParameters(theme: account.telegramApplicationContext.currentPresentationData.with { $0 }.theme, accountPeerId: account.peerId, peerId: peer.id, letters: peer.displayLetters, font: self.font, icon: icon, explicitColorIndex: nil, hasImage: true) + if case .editAvatarIcon = icon { + if self.editOverlayNode == nil { + let editOverlayNode = AvatarEditOverlayNode() + editOverlayNode.frame = self.imageNode.frame + self.addSubnode(editOverlayNode) + + self.editOverlayNode = editOverlayNode + } + self.editOverlayNode?.isHidden = false + } + + parameters = AvatarNodeParameters(theme: theme, accountPeerId: account.peerId, peerId: peer.id, letters: peer.displayLetters, font: self.font, icon: icon, explicitColorIndex: nil, hasImage: true) } else { self.imageReady.set(.single(true)) self.displaySuspended = false @@ -189,7 +245,8 @@ public final class AvatarNode: ASDisplayNode { self.imageNode.contents = nil } - parameters = AvatarNodeParameters(theme: account.telegramApplicationContext.currentPresentationData.with { $0 }.theme, accountPeerId: account.peerId, peerId: peer.id, letters: peer.displayLetters, font: self.font, icon: icon, explicitColorIndex: nil, hasImage: false) + self.editOverlayNode?.isHidden = true + parameters = AvatarNodeParameters(theme: theme, accountPeerId: account.peerId, peerId: peer.id, letters: peer.displayLetters, font: self.font, icon: icon, explicitColorIndex: nil, hasImage: false) } if self.parameters == nil || self.parameters != parameters { self.parameters = parameters diff --git a/TelegramUI/ChangePhoneNumberController.swift b/TelegramUI/ChangePhoneNumberController.swift index 7654b7c525..3daf40b942 100644 --- a/TelegramUI/ChangePhoneNumberController.swift +++ b/TelegramUI/ChangePhoneNumberController.swift @@ -114,18 +114,17 @@ final class ChangePhoneNumberController: ViewController { let text: String switch error { - //TODO case .limitExceeded: - text = "You have requested authorization code too many times. Please try again later." + text = presentationData.strings.Login_CodeFloodError case .invalidPhoneNumber: - text = "The phone number you entered is not valid. Please enter the correct number along with your area code." + text = presentationData.strings.Login_InvalidPhoneError case .phoneNumberOccupied: - text = "The number \(number) is already connected to a Telegram account. Please delete that account before migrating to the new number." + text = presentationData.strings.ChangePhone_ErrorOccupied(number).0 case .generic: - text = "An error occurred. Please try again later." + text = presentationData.strings.Login_UnknownError } - strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationTheme: presentationData.theme), title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: "OK", action: {})]), in: .window(.root)) + strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationTheme: presentationData.theme), title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root)) } })) } else { diff --git a/TelegramUI/ChatController.swift b/TelegramUI/ChatController.swift index 9b59fdb1db..cdf68a51c0 100644 --- a/TelegramUI/ChatController.swift +++ b/TelegramUI/ChatController.swift @@ -180,7 +180,7 @@ public final class ChatController: TelegramController, UIViewControllerPreviewin self.messageId = messageId self.botStart = botStart - let locationBroadcastPanelSource: LocationBroadcastPanelSource + var locationBroadcastPanelSource: LocationBroadcastPanelSource switch chatLocation { case let .peer(peerId): @@ -199,6 +199,8 @@ public final class ChatController: TelegramController, UIViewControllerPreviewin var enableMediaAccessoryPanel = false if case .standard = mode { enableMediaAccessoryPanel = true + } else { + locationBroadcastPanelSource = .none } let navigationBarPresentationData: NavigationBarPresentationData? switch mode { diff --git a/TelegramUI/ChatInterfaceStateNavigationButtons.swift b/TelegramUI/ChatInterfaceStateNavigationButtons.swift index b13ac47354..a54f8d679f 100644 --- a/TelegramUI/ChatInterfaceStateNavigationButtons.swift +++ b/TelegramUI/ChatInterfaceStateNavigationButtons.swift @@ -49,7 +49,8 @@ func rightNavigationButtonForChatInterfaceState(_ presentationInterfaceState: Ch } } - if let peer = presentationInterfaceState.renderedPeer?.peer { + if case .standard(true) = presentationInterfaceState.mode { + } else if let peer = presentationInterfaceState.renderedPeer?.peer { if presentationInterfaceState.accountPeerId == peer.id { return ChatNavigationButton(action: .search, buttonItem: UIBarButtonItem(image: PresentationResourcesRootController.navigationCompactSearchIcon(presentationInterfaceState.theme), style: .plain, target: target, action: selector)) } diff --git a/TelegramUI/ChatMessageBubbleItemNode.swift b/TelegramUI/ChatMessageBubbleItemNode.swift index ce8aad691c..d1213cea85 100644 --- a/TelegramUI/ChatMessageBubbleItemNode.swift +++ b/TelegramUI/ChatMessageBubbleItemNode.swift @@ -1506,7 +1506,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView { if let sourceMessageId = forwardInfo.sourceMessageId { item.controllerInteraction.navigateToMessage(item.message.id, sourceMessageId) } else { - item.controllerInteraction.openPeer(forwardInfo.source?.id ?? forwardInfo.author.id, .chat(textInputState: nil, messageId: nil), nil) + item.controllerInteraction.openPeer(forwardInfo.source?.id ?? forwardInfo.author.id, .info, nil) } return } diff --git a/TelegramUI/DateSelectionActionSheetController.swift b/TelegramUI/DateSelectionActionSheetController.swift index f2eed803af..1981bc1ee2 100644 --- a/TelegramUI/DateSelectionActionSheetController.swift +++ b/TelegramUI/DateSelectionActionSheetController.swift @@ -14,7 +14,7 @@ final class DateSelectionActionSheetController: ActionSheetController { return self._ready } - init(theme: PresentationTheme, strings: PresentationStrings, currentValue: Int32, emptyTitle: String? = nil, applyValue: @escaping (Int32?) -> Void) { + init(theme: PresentationTheme, strings: PresentationStrings, currentValue: Int32, minimumDate: Date? = nil, maximumDate: Date? = nil, emptyTitle: String? = nil, applyValue: @escaping (Int32?) -> Void) { self.theme = theme self.strings = strings @@ -24,7 +24,7 @@ final class DateSelectionActionSheetController: ActionSheetController { var updatedValue = currentValue var items: [ActionSheetItem] = [] - items.append(DateSelectionActionSheetItem(strings: strings, currentValue: currentValue, valueChanged: { value in + items.append(DateSelectionActionSheetItem(strings: strings, currentValue: currentValue, minimumDate: minimumDate, maximumDate: maximumDate, valueChanged: { value in updatedValue = value })) if let emptyTitle = emptyTitle { @@ -56,16 +56,20 @@ private final class DateSelectionActionSheetItem: ActionSheetItem { let strings: PresentationStrings let currentValue: Int32 + let minimumDate: Date? + let maximumDate: Date? let valueChanged: (Int32) -> Void - - init(strings: PresentationStrings, currentValue: Int32, valueChanged: @escaping (Int32) -> Void) { + + init(strings: PresentationStrings, currentValue: Int32, minimumDate: Date?, maximumDate: Date?, valueChanged: @escaping (Int32) -> Void) { self.strings = strings self.currentValue = roundDateToDays(currentValue) + self.minimumDate = minimumDate + self.maximumDate = maximumDate self.valueChanged = valueChanged } func node(theme: ActionSheetControllerTheme) -> ActionSheetItemNode { - return DateSelectionActionSheetItemNode(theme: theme, strings: self.strings, currentValue: self.currentValue, valueChanged: self.valueChanged) + return DateSelectionActionSheetItemNode(theme: theme, strings: self.strings, currentValue: self.currentValue, minimumDate: self.minimumDate, maximumDate: self.maximumDate, valueChanged: self.valueChanged) } func updateNode(_ node: ActionSheetItemNode) { @@ -79,7 +83,7 @@ private final class DateSelectionActionSheetItemNode: ActionSheetItemNode { private let valueChanged: (Int32) -> Void private let pickerView: UIDatePicker - init(theme: ActionSheetControllerTheme, strings: PresentationStrings, currentValue: Int32, valueChanged: @escaping (Int32) -> Void) { + init(theme: ActionSheetControllerTheme, strings: PresentationStrings, currentValue: Int32, minimumDate: Date?, maximumDate: Date?, valueChanged: @escaping (Int32) -> Void) { self.theme = theme self.strings = strings self.valueChanged = valueChanged @@ -88,7 +92,14 @@ private final class DateSelectionActionSheetItemNode: ActionSheetItemNode { self.pickerView.datePickerMode = .date self.pickerView.date = Date(timeIntervalSince1970: Double(roundDateToDays(currentValue))) self.pickerView.locale = localeWithStrings(strings) - self.pickerView.maximumDate = Date(timeIntervalSince1970: Double(Int32.max - 1)) + if let minimumDate = minimumDate { + self.pickerView.minimumDate = minimumDate + } + if let maximumDate = minimumDate { + self.pickerView.maximumDate = maximumDate + } else { + self.pickerView.maximumDate = Date(timeIntervalSince1970: Double(Int32.max - 1)) + } self.pickerView.setValue(theme.primaryTextColor, forKey: "textColor") diff --git a/TelegramUI/EditSettingsController.swift b/TelegramUI/EditSettingsController.swift index 4b1ace32e2..35717ec818 100644 --- a/TelegramUI/EditSettingsController.swift +++ b/TelegramUI/EditSettingsController.swift @@ -34,8 +34,8 @@ private enum SettingsEntry: ItemListNodeEntry { case bioText(PresentationTheme, String, String) case bioInfo(PresentationTheme, String) - case username(PresentationTheme, String, String) case phoneNumber(PresentationTheme, String, String) + case username(PresentationTheme, String, String) case logOut(PresentationTheme, String) @@ -45,7 +45,7 @@ private enum SettingsEntry: ItemListNodeEntry { return SettingsSection.info.rawValue case .bioText, .bioInfo: return SettingsSection.bio.rawValue - case .username, .phoneNumber: + case .phoneNumber, .username: return SettingsSection.personalData.rawValue case .logOut: return SettingsSection.logOut.rawValue @@ -62,9 +62,9 @@ private enum SettingsEntry: ItemListNodeEntry { return 2 case .bioInfo: return 3 - case .username: - return 4 case .phoneNumber: + return 4 + case .username: return 5 case .logOut: return 6 @@ -123,14 +123,14 @@ private enum SettingsEntry: ItemListNodeEntry { } else { return false } - case let .username(lhsTheme, lhsText, lhsAddress): - if case let .username(rhsTheme, rhsText, rhsAddress) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsAddress == rhsAddress { + case let .phoneNumber(lhsTheme, lhsText, lhsNumber): + if case let .phoneNumber(rhsTheme, rhsText, rhsNumber) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsNumber == rhsNumber { return true } else { return false } - case let .phoneNumber(lhsTheme, lhsText, lhsNumber): - if case let .phoneNumber(rhsTheme, rhsText, rhsNumber) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsNumber == rhsNumber { + case let .username(lhsTheme, lhsText, lhsAddress): + if case let .username(rhsTheme, rhsText, rhsAddress) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsAddress == rhsAddress { return true } else { return false @@ -166,14 +166,14 @@ private enum SettingsEntry: ItemListNodeEntry { }) case let .bioInfo(theme, text): return ItemListTextItem(theme: theme, text: .plain(text), sectionId: self.section) - case let .username(theme, text, address): - return ItemListDisclosureItem(theme: theme, title: text, label: address, sectionId: ItemListSectionId(self.section), style: .blocks, action: { - arguments.presentController(usernameSetupController(account: arguments.account)) - }) case let .phoneNumber(theme, text, number): return ItemListDisclosureItem(theme: theme, title: text, label: number, sectionId: ItemListSectionId(self.section), style: .blocks, action: { arguments.pushController(ChangePhoneNumberIntroController(account: arguments.account, phoneNumber: number)) }) + case let .username(theme, text, address): + return ItemListDisclosureItem(theme: theme, title: text, label: address, sectionId: ItemListSectionId(self.section), style: .blocks, action: { + arguments.presentController(usernameSetupController(account: arguments.account)) + }) case let .logOut(theme, text): return ItemListActionItem(theme: theme, title: text, kind: .destructive, alignment: .center, sectionId: ItemListSectionId(self.section), style: .blocks, action: { arguments.logout() @@ -248,11 +248,10 @@ private func editSettingsEntries(presentationData: PresentationData, state: Edit entries.append(.bioText(presentationData.theme, state.editingBioText, presentationData.strings.UserInfo_About_Placeholder)) entries.append(.bioInfo(presentationData.theme, presentationData.strings.Settings_About_Help)) - entries.append(.username(presentationData.theme, presentationData.strings.Settings_Username, peer.addressName == nil ? "" : ("@" + peer.addressName!))) - if let phone = peer.phone { entries.append(.phoneNumber(presentationData.theme, presentationData.strings.Settings_PhoneNumber, formatPhoneNumber(phone))) } + entries.append(.username(presentationData.theme, presentationData.strings.Settings_Username, peer.addressName == nil ? "" : ("@" + peer.addressName!))) entries.append(.logOut(presentationData.theme, presentationData.strings.Settings_Logout)) } @@ -463,7 +462,7 @@ func editSettingsController(account: Account, currentName: ItemListAvatarAndName } let controller = ItemListController(account: account, state: signal, tabBarItem: (account.applicationContext as! TelegramApplicationContext).presentationData |> map { presentationData in - return ItemListControllerTabBarItem(title: presentationData.strings.Settings_Title, image: PresentationResourcesRootController.tabSettingsIcon(presentationData.theme), selectedImage: PresentationResourcesRootController.tabSettingsSelectedIcon(presentationData.theme)) + return ItemListControllerTabBarItem(title: presentationData.strings.EditProfile_Title, image: PresentationResourcesRootController.tabSettingsIcon(presentationData.theme), selectedImage: PresentationResourcesRootController.tabSettingsSelectedIcon(presentationData.theme)) }) pushControllerImpl = { [weak controller] value in (controller?.navigationController as? NavigationController)?.pushViewController(value) diff --git a/TelegramUI/FormControllerTextInputItem.swift b/TelegramUI/FormControllerTextInputItem.swift index f4d5c0db42..7b901e21cd 100644 --- a/TelegramUI/FormControllerTextInputItem.swift +++ b/TelegramUI/FormControllerTextInputItem.swift @@ -5,17 +5,26 @@ import Display private let textFont = Font.regular(17.0) private let errorFont = Font.regular(13.0) +enum FormControllerTextInputItemType: Equatable { + case regular(capitalization: UITextAutocapitalizationType, autocorrection: Bool) + case latin + case email + case number +} + final class FormControllerTextInputItem: FormControllerItem { let title: String let text: String let placeholder: String + let type: FormControllerTextInputItemType let error: String? let textUpdated: (String) -> Void - init(title: String, text: String, placeholder: String, error: String? = nil, textUpdated: @escaping (String) -> Void) { + init(title: String, text: String, placeholder: String, type: FormControllerTextInputItemType, error: String? = nil, textUpdated: @escaping (String) -> Void) { self.title = title self.text = text self.placeholder = placeholder + self.type = type self.error = error self.textUpdated = textUpdated } @@ -81,6 +90,39 @@ final class FormControllerTextInputItemNode: FormBlockItemNode 0 { + bottomInset -= 12.0 + } let buttonHeight: CGFloat = 57.0 let sectionSpacing: CGFloat = 8.0 let titleAreaHeight: CGFloat = 64.0 @@ -239,7 +242,7 @@ final class JoinLinkPreviewControllerNode: ViewControllerTracingNode, UIScrollVi let contentContainerFrame = CGRect(origin: CGPoint(x: sideInset, y: insets.top), size: CGSize(width: width, height: maximumContentHeight)) let contentFrame = contentContainerFrame.insetBy(dx: 0.0, dy: 0.0) - var bottomGridInset = buttonHeight + let bottomGridInset = buttonHeight self.containerLayout = (layout, navigationBarHeight, bottomGridInset) self.scheduledLayoutTransitionRequest = nil @@ -272,7 +275,10 @@ final class JoinLinkPreviewControllerNode: ViewControllerTracingNode, UIScrollVi insets.top = max(10.0, insets.top) let cleanInsets = layout.insets(options: [.statusBar]) - let bottomInset: CGFloat = 10.0 + cleanInsets.bottom + var bottomInset: CGFloat = 10.0 + cleanInsets.bottom + if insets.bottom > 0 { + bottomInset -= 12.0 + } let buttonHeight: CGFloat = 57.0 let sectionSpacing: CGFloat = 8.0 diff --git a/TelegramUI/LegacyLocationController.swift b/TelegramUI/LegacyLocationController.swift index 1a5d00f217..fd45972edc 100644 --- a/TelegramUI/LegacyLocationController.swift +++ b/TelegramUI/LegacyLocationController.swift @@ -126,7 +126,7 @@ func legacyLocationController(message: Message, mapMedia: TelegramMediaMap, acco let presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 } - let legacyController = LegacyController(presentation: .navigation, theme: presentationData.theme, presentationData: presentationData) + let legacyController = LegacyController(presentation: modal ? .modal(animateIn: true) : .navigation, theme: presentationData.theme, presentationData: presentationData) let legacyMessage = makeLegacyMessage(message) diff --git a/TelegramUI/LegacyLocationPicker.swift b/TelegramUI/LegacyLocationPicker.swift index 55a2d3afe8..49e2a12776 100644 --- a/TelegramUI/LegacyLocationPicker.swift +++ b/TelegramUI/LegacyLocationPicker.swift @@ -30,6 +30,7 @@ func legacyLocationPickerController(account: Account, selfPeer: Peer, peer: Peer legacyController?.dismiss() }, rootController: nil) legacyController.bind(controller: navigationController) + legacyController.supportedOrientations = ViewControllerSupportedOrientations(regularSize: .all, compactSize: .portrait) controller.locationPicked = { [weak legacyController] coordinate, venue in sendLocation(coordinate, venue.flatMap { venue in return MapVenue(title: venue.title, address: venue.address, provider: venue.provider, id: venue.venueId, type: venue.type) diff --git a/TelegramUI/SecureIdDocumentFormControllerNode.swift b/TelegramUI/SecureIdDocumentFormControllerNode.swift index 24907020f9..aee80dc750 100644 --- a/TelegramUI/SecureIdDocumentFormControllerNode.swift +++ b/TelegramUI/SecureIdDocumentFormControllerNode.swift @@ -1555,19 +1555,19 @@ enum SecureIdDocumentFormEntry: FormControllerEntry { } return FormControllerHeaderItem(text: text) case let .identifier(value, error): - return FormControllerTextInputItem(title: strings.Passport_Identity_DocumentNumber, text: value, placeholder: strings.Passport_Identity_DocumentNumberPlaceholder, error: error, textUpdated: { text in + return FormControllerTextInputItem(title: strings.Passport_Identity_DocumentNumber, text: value, placeholder: strings.Passport_Identity_DocumentNumberPlaceholder, type: .regular(capitalization: .words, autocorrection: false), error: error, textUpdated: { text in params.updateText(.identifier, text) }) case let .firstName(value, error): - return FormControllerTextInputItem(title: strings.Passport_Identity_Name, text: value, placeholder: strings.Passport_Identity_NamePlaceholder, error: error, textUpdated: { text in + return FormControllerTextInputItem(title: strings.Passport_Identity_Name, text: value, placeholder: strings.Passport_Identity_NamePlaceholder, type: .latin, error: error, textUpdated: { text in params.updateText(.firstName, text) }) case let .middleName(value, error): - return FormControllerTextInputItem(title: strings.Passport_Identity_MiddleName, text: value, placeholder: strings.Passport_Identity_MiddleNamePlaceholder, error: error, textUpdated: { text in + return FormControllerTextInputItem(title: strings.Passport_Identity_MiddleName, text: value, placeholder: strings.Passport_Identity_MiddleNamePlaceholder, type: .latin, error: error, textUpdated: { text in params.updateText(.middleName, text) }) case let .lastName(value, error): - return FormControllerTextInputItem(title: strings.Passport_Identity_Surname, text: value, placeholder: strings.Passport_Identity_SurnamePlaceholder, error: error, textUpdated: { text in + return FormControllerTextInputItem(title: strings.Passport_Identity_Surname, text: value, placeholder: strings.Passport_Identity_SurnamePlaceholder, type: .latin, error: error, textUpdated: { text in params.updateText(.lastName, text) }) case let .nativeInfoHeader(language): @@ -1579,23 +1579,23 @@ enum SecureIdDocumentFormEntry: FormControllerEntry { } return FormControllerHeaderItem(text: title) case let .nativeFirstName(value, error): - return FormControllerTextInputItem(title: strings.Passport_Identity_Name, text: value, placeholder: strings.Passport_Identity_NamePlaceholder, error: error, textUpdated: { text in + return FormControllerTextInputItem(title: strings.Passport_Identity_Name, text: value, placeholder: strings.Passport_Identity_NamePlaceholder, type: .regular(capitalization: .words, autocorrection: false), error: error, textUpdated: { text in params.updateText(.nativeFirstName, text) }) case let .nativeMiddleName(value, error): - return FormControllerTextInputItem(title: strings.Passport_Identity_MiddleName, text: value, placeholder: strings.Passport_Identity_MiddleNamePlaceholder, error: error, textUpdated: { text in + return FormControllerTextInputItem(title: strings.Passport_Identity_MiddleName, text: value, placeholder: strings.Passport_Identity_MiddleNamePlaceholder, type: .regular(capitalization: .words, autocorrection: false), error: error, textUpdated: { text in params.updateText(.nativeMiddleName, text) }) case let .nativeLastName(value, error): - return FormControllerTextInputItem(title: strings.Passport_Identity_Surname, text: value, placeholder: strings.Passport_Identity_SurnamePlaceholder, error: error, textUpdated: { text in + return FormControllerTextInputItem(title: strings.Passport_Identity_Surname, text: value, placeholder: strings.Passport_Identity_SurnamePlaceholder, type: .regular(capitalization: .words, autocorrection: false), error: error, textUpdated: { text in params.updateText(.nativeLastName, text) }) case let .nativeInfo(language): let text: String - if !language.isEmpty, let value = strings.dict["Passport.Language.\(language)"] { - text = strings.Passport_Identity_NativeNameGenericHelp(value).0.uppercased() - } else { + if !language.isEmpty, let _ = strings.dict["Passport.Language.\(language)"] { text = strings.Passport_Identity_NativeNameHelp + } else { + text = strings.Passport_Identity_NativeNameGenericHelp("").0 } return FormControllerTextItem(text: text) case let .gender(value, error): @@ -1632,23 +1632,23 @@ enum SecureIdDocumentFormEntry: FormControllerEntry { params.deleteValue() }) case let .street1(value, error): - return FormControllerTextInputItem(title: strings.Passport_Address_Street, text: value, placeholder: strings.Passport_Address_Street1Placeholder, error: error, textUpdated: { text in + return FormControllerTextInputItem(title: strings.Passport_Address_Street, text: value, placeholder: strings.Passport_Address_Street1Placeholder, type: .regular(capitalization: .words, autocorrection: false), error: error, textUpdated: { text in params.updateText(.street1, text) }) case let .street2(value, error): - return FormControllerTextInputItem(title: "", text: value, placeholder: strings.Passport_Address_Street2Placeholder, error: error, textUpdated: { text in + return FormControllerTextInputItem(title: "", text: value, placeholder: strings.Passport_Address_Street2Placeholder, type: .regular(capitalization: .words, autocorrection: false), error: error, textUpdated: { text in params.updateText(.street2, text) }) case let .city(value, error): - return FormControllerTextInputItem(title: strings.Passport_Address_City, text: value, placeholder: strings.Passport_Address_CityPlaceholder, error: error, textUpdated: { text in + return FormControllerTextInputItem(title: strings.Passport_Address_City, text: value, placeholder: strings.Passport_Address_CityPlaceholder, type: .regular(capitalization: .words, autocorrection: false), error: error, textUpdated: { text in params.updateText(.city, text) }) case let .state(value, error): - return FormControllerTextInputItem(title: strings.Passport_Address_Region, text: value, placeholder: strings.Passport_Address_RegionPlaceholder, error: error, textUpdated: { text in + return FormControllerTextInputItem(title: strings.Passport_Address_Region, text: value, placeholder: strings.Passport_Address_RegionPlaceholder, type: .regular(capitalization: .words, autocorrection: false), error: error, textUpdated: { text in params.updateText(.state, text) }) case let .postcode(value, error): - return FormControllerTextInputItem(title: strings.Passport_Address_Postcode, text: value, placeholder: strings.Passport_Address_PostcodePlaceholder, error: error, textUpdated: { text in + return FormControllerTextInputItem(title: strings.Passport_Address_Postcode, text: value, placeholder: strings.Passport_Address_PostcodePlaceholder, type: .regular(capitalization: .allCharacters, autocorrection: false), error: error, textUpdated: { text in params.updateText(.postcode, text) }) case .requestedDocumentsHeader: @@ -1883,10 +1883,26 @@ final class SecureIdDocumentFormControllerNode: FormControllerNode 0 { + bottomInset -= 12.0 + } + let buttonHeight: CGFloat = 57.0 let sectionSpacing: CGFloat = 8.0 let titleAreaHeight: CGFloat = 64.0 @@ -378,7 +382,10 @@ final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate insets.top = max(10.0, insets.top) let cleanInsets = layout.insets(options: [.statusBar]) - let bottomInset: CGFloat = 10.0 + cleanInsets.bottom + var bottomInset: CGFloat = 10.0 + cleanInsets.bottom + if insets.bottom > 0 { + bottomInset -= 12.0 + } let buttonHeight: CGFloat = 57.0 let sectionSpacing: CGFloat = 8.0 diff --git a/TelegramUI/StickerPackPreviewControllerNode.swift b/TelegramUI/StickerPackPreviewControllerNode.swift index 5cb2877343..7f02de93b9 100644 --- a/TelegramUI/StickerPackPreviewControllerNode.swift +++ b/TelegramUI/StickerPackPreviewControllerNode.swift @@ -245,7 +245,11 @@ final class StickerPackPreviewControllerNode: ViewControllerTracingNode, UIScrol transition.updateFrame(node: self.dimNode, frame: CGRect(origin: CGPoint(), size: layout.size)) - let bottomInset: CGFloat = 10.0 + cleanInsets.bottom + var bottomInset: CGFloat = 10.0 + cleanInsets.bottom + if insets.bottom > 0 { + bottomInset -= 12.0 + } + let buttonHeight: CGFloat = 57.0 let sectionSpacing: CGFloat = 8.0 let titleAreaHeight: CGFloat = 51.0 @@ -352,7 +356,11 @@ final class StickerPackPreviewControllerNode: ViewControllerTracingNode, UIScrol insets.top = max(10.0, insets.top) let cleanInsets = layout.insets(options: [.statusBar]) - let bottomInset: CGFloat = 10.0 + cleanInsets.bottom + var bottomInset: CGFloat = 10.0 + cleanInsets.bottom + if insets.bottom > 0 { + bottomInset -= 12.0 + } + let buttonHeight: CGFloat = 57.0 let sectionSpacing: CGFloat = 8.0 let titleAreaHeight: CGFloat = 51.0 diff --git a/TelegramUI/TwoStepVerificationPasswordEntryController.swift b/TelegramUI/TwoStepVerificationPasswordEntryController.swift index 2a65fecd68..bb3cd3362d 100644 --- a/TelegramUI/TwoStepVerificationPasswordEntryController.swift +++ b/TelegramUI/TwoStepVerificationPasswordEntryController.swift @@ -44,7 +44,7 @@ private enum TwoStepVerificationPasswordEntryEntry: ItemListNodeEntry { case hintTitle(PresentationTheme, String) case hintEntry(PresentationTheme, String) - case emailEntry(PresentationTheme, String) + case emailEntry(PresentationTheme, PresentationStrings, String) case emailInfo(PresentationTheme, String) var section: ItemListSectionId { @@ -94,8 +94,8 @@ private enum TwoStepVerificationPasswordEntryEntry: ItemListNodeEntry { } else { return false } - case let .emailEntry(lhsTheme, lhsText): - if case let .emailEntry(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText { + case let .emailEntry(lhsTheme, lhsStrings, lhsText): + if case let .emailEntry(rhsTheme, rhsStrings, rhsText) = rhs, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsText == rhsText { return true } else { return false @@ -131,8 +131,8 @@ private enum TwoStepVerificationPasswordEntryEntry: ItemListNodeEntry { }, action: { arguments.next() }) - case let .emailEntry(theme, text): - return ItemListSingleLineInputItem(theme: theme, title: NSAttributedString(string: "E-Mail", textColor: .black), text: text, placeholder: "", type: .email, spacing: 10.0, tag: TwoStepVerificationPasswordEntryTag.input, sectionId: self.section, textUpdated: { updatedText in + case let .emailEntry(theme, strings, text): + return ItemListSingleLineInputItem(theme: theme, title: NSAttributedString(string: strings.TwoStepAuth_Email, textColor: .black), text: text, placeholder: "", type: .email, spacing: 10.0, tag: TwoStepVerificationPasswordEntryTag.input, sectionId: self.section, textUpdated: { updatedText in arguments.updateEntryText(updatedText) }, action: { arguments.next() @@ -235,7 +235,7 @@ private func twoStepVerificationPasswordEntryControllerEntries(presentationData: entries.append(.hintTitle(presentationData.theme, presentationData.strings.TwoStepAuth_SetupHint)) entries.append(.hintEntry(presentationData.theme, text)) case let .email(_, _, text): - entries.append(.emailEntry(presentationData.theme, text)) + entries.append(.emailEntry(presentationData.theme, presentationData.strings, text)) entries.append(.emailInfo(presentationData.theme, presentationData.strings.TwoStepAuth_EmailHelp)) } @@ -341,11 +341,11 @@ func twoStepVerificationPasswordEntryController(account: Account, mode: TwoStepV let alertText: String switch error { case .generic: - alertText = "An error occurred." + alertText = presentationData.strings.Login_UnknownError case .invalidEmail: - alertText = "Please enter valid e-mail address." + alertText = presentationData.strings.TwoStepAuth_EmailInvalid } - presentControllerImpl?(standardTextAlertController(theme: AlertControllerTheme(presentationTheme: presentationData.theme), title: nil, text: alertText, actions: [TextAlertAction(type: .defaultAction, title: "OK", action: {})]), ViewControllerPresentationArguments(presentationAnimation: .modalSheet)) + presentControllerImpl?(standardTextAlertController(theme: AlertControllerTheme(presentationTheme: presentationData.theme), title: nil, text: alertText, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), ViewControllerPresentationArguments(presentationAnimation: .modalSheet)) })) case let .setupEmail(password): updatePasswordDisposable.set((updateTwoStepVerificationEmail(account: account, currentPassword: password, updatedEmail: email) |> deliverOnMainQueue).start(next: { update in @@ -366,16 +366,16 @@ func twoStepVerificationPasswordEntryController(account: Account, mode: TwoStepV let alertText: String switch error { case .generic: - alertText = "An error occurred." + alertText = presentationData.strings.Login_UnknownError case .invalidEmail: - alertText = "Please enter valid e-mail address." + alertText = presentationData.strings.TwoStepAuth_EmailInvalid } - presentControllerImpl?(standardTextAlertController(theme: AlertControllerTheme(presentationTheme: presentationData.theme), title: nil, text: alertText, actions: [TextAlertAction(type: .defaultAction, title: "OK", action: {})]), ViewControllerPresentationArguments(presentationAnimation: .modalSheet)) + presentControllerImpl?(standardTextAlertController(theme: AlertControllerTheme(presentationTheme: presentationData.theme), title: nil, text: alertText, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), ViewControllerPresentationArguments(presentationAnimation: .modalSheet)) })) } } else if invalidReentry { let presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 } - presentControllerImpl?(standardTextAlertController(theme: AlertControllerTheme(presentationTheme: presentationData.theme), title: nil, text: "Passwords don't match.\nPlease try again.", actions: [TextAlertAction(type: .defaultAction, title: "OK", action: {})]), ViewControllerPresentationArguments(presentationAnimation: .modalSheet)) + presentControllerImpl?(standardTextAlertController(theme: AlertControllerTheme(presentationTheme: presentationData.theme), title: nil, text: presentationData.strings.TwoStepAuth_SetupPasswordConfirmFailed, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), ViewControllerPresentationArguments(presentationAnimation: .modalSheet)) } } diff --git a/TelegramUI/TwoStepVerificationUnlockController.swift b/TelegramUI/TwoStepVerificationUnlockController.swift index d701bf2aee..e9af6dbf58 100644 --- a/TelegramUI/TwoStepVerificationUnlockController.swift +++ b/TelegramUI/TwoStepVerificationUnlockController.swift @@ -223,7 +223,7 @@ private struct TwoStepVerificationUnlockSettingsControllerState: Equatable { } } -private func twoStepVerificationUnlockSettingsControllerEntries(presentationData: PresentationData, state: TwoStepVerificationUnlockSettingsControllerState,data: TwoStepVerificationUnlockSettingsControllerData) -> [TwoStepVerificationUnlockSettingsEntry] { +private func twoStepVerificationUnlockSettingsControllerEntries(presentationData: PresentationData, state: TwoStepVerificationUnlockSettingsControllerState, data: TwoStepVerificationUnlockSettingsControllerData) -> [TwoStepVerificationUnlockSettingsEntry] { var entries: [TwoStepVerificationUnlockSettingsEntry] = [] switch data { @@ -237,7 +237,7 @@ private func twoStepVerificationUnlockSettingsControllerEntries(presentationData } else { entries.append(.pendingEmailInfo(presentationData.theme, presentationData.strings.TwoStepAuth_ConfirmationText + "\n\n\(pendingEmailPattern)\n\n[" + presentationData.strings.TwoStepAuth_ConfirmationAbort + "]()")) } - case let .set(hint, _, _): + case let .set(hint, _, _, _): entries.append(.passwordEntry(presentationData.theme, presentationData.strings.TwoStepAuth_EnterPasswordPassword, state.passwordText)) if hint.isEmpty { entries.append(.passwordEntryInfo(presentationData.theme, presentationData.strings.TwoStepAuth_EnterPasswordHelp + "\n\n[" + presentationData.strings.TwoStepAuth_EnterPasswordForgot + "](forgot)")) @@ -246,7 +246,7 @@ private func twoStepVerificationUnlockSettingsControllerEntries(presentationData } } } - case let .manage(_, emailSet, pendingEmailPattern): + case let .manage(_, emailSet, pendingEmailPattern, _): entries.append(.changePassword(presentationData.theme, presentationData.strings.TwoStepAuth_ChangePassword)) entries.append(.turnPasswordOff(presentationData.theme, presentationData.strings.TwoStepAuth_RemovePassword)) entries.append(.setupRecoveryEmail(presentationData.theme, emailSet ? presentationData.strings.TwoStepAuth_ChangeEmail : presentationData.strings.TwoStepAuth_SetupEmail)) @@ -262,12 +262,12 @@ private func twoStepVerificationUnlockSettingsControllerEntries(presentationData enum TwoStepVerificationUnlockSettingsControllerMode { case access - case manage(password: String, email: String, pendingEmailPattern: String) + case manage(password: String, email: String, pendingEmailPattern: String, hasSecureValues: Bool) } private enum TwoStepVerificationUnlockSettingsControllerData { case access(configuration: TwoStepVerificationConfiguration?) - case manage(password: String, emailSet: Bool, pendingEmailPattern: String) + case manage(password: String, emailSet: Bool, pendingEmailPattern: String, hasSecureValues: Bool) } func twoStepVerificationUnlockSettingsController(account: Account, mode: TwoStepVerificationUnlockSettingsControllerMode) -> ViewController { @@ -298,8 +298,8 @@ func twoStepVerificationUnlockSettingsController(account: Account, mode: TwoStep switch mode { case .access: dataPromise.set(.single(TwoStepVerificationUnlockSettingsControllerData.access(configuration: nil)) |> then(twoStepVerificationConfiguration(account: account) |> map { TwoStepVerificationUnlockSettingsControllerData.access(configuration: $0) })) - case let .manage(password, email, pendingEmailPattern): - dataPromise.set(.single(.manage(password: password, emailSet: !email.isEmpty, pendingEmailPattern: pendingEmailPattern))) + case let .manage(password, email, pendingEmailPattern, hasSecureValues): + dataPromise.set(.single(.manage(password: password, emailSet: !email.isEmpty, pendingEmailPattern: pendingEmailPattern, hasSecureValues: hasSecureValues))) } let arguments = TwoStepVerificationUnlockSettingsControllerArguments(updatePasswordText: { updatedText in @@ -313,7 +313,7 @@ func twoStepVerificationUnlockSettingsController(account: Account, mode: TwoStep if let configuration = configuration { let presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 } switch configuration { - case let .set(_, hasRecoveryEmail, _): + case let .set(_, hasRecoveryEmail, _, _): if hasRecoveryEmail { updateState { $0.withUpdatedChecking(true) @@ -336,7 +336,7 @@ func twoStepVerificationUnlockSettingsController(account: Account, mode: TwoStep presentControllerImpl?(standardTextAlertController(theme: AlertControllerTheme(presentationTheme: presentationData.theme), title: nil, text: presentationData.strings.Login_UnknownError, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), ViewControllerPresentationArguments(presentationAnimation: .modalSheet)) })) } else { - presentControllerImpl?(standardTextAlertController(theme: AlertControllerTheme(presentationTheme: presentationData.theme), title: nil, text: "Since you haven't provided a recovery e-mail when setting up your password, your remaining options are either to remember your password or to reset your account.", actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), ViewControllerPresentationArguments(presentationAnimation: .modalSheet)) + presentControllerImpl?(standardTextAlertController(theme: AlertControllerTheme(presentationTheme: presentationData.theme), title: nil, text: presentationData.strings.TwoStepAuth_RecoveryUnavailable, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), ViewControllerPresentationArguments(presentationAnimation: .modalSheet)) } case .notSet: break @@ -361,7 +361,7 @@ func twoStepVerificationUnlockSettingsController(account: Account, mode: TwoStep if let pendingEmailPattern = updatedPassword.pendingEmailPattern { dataPromise.set(.single(TwoStepVerificationUnlockSettingsControllerData.access(configuration: TwoStepVerificationConfiguration.notSet(pendingEmailPattern: pendingEmailPattern)))) } else { - dataPromise.set(.single(TwoStepVerificationUnlockSettingsControllerData.manage(password: updatedPassword.password, emailSet: false, pendingEmailPattern: ""))) + dataPromise.set(.single(TwoStepVerificationUnlockSettingsControllerData.manage(password: updatedPassword.password, emailSet: false, pendingEmailPattern: "", hasSecureValues: false))) } controller?.dismiss() } @@ -370,69 +370,80 @@ func twoStepVerificationUnlockSettingsController(account: Account, mode: TwoStep break } } - case let .manage(password, emailSet, pendingEmailPattern): + case let .manage(password, emailSet, pendingEmailPattern, hasSecureValues): let result = Promise() let controller = twoStepVerificationPasswordEntryController(account: account, mode: .change(current: password), result: result) presentControllerImpl?(controller, ViewControllerPresentationArguments(presentationAnimation: .modalSheet)) setupResultDisposable.set((result.get() |> take(1) |> deliverOnMainQueue).start(next: { [weak controller] updatedPassword in if let updatedPassword = updatedPassword { - dataPromise.set(.single(TwoStepVerificationUnlockSettingsControllerData.manage(password: updatedPassword.password, emailSet: emailSet, pendingEmailPattern: pendingEmailPattern))) + dataPromise.set(.single(TwoStepVerificationUnlockSettingsControllerData.manage(password: updatedPassword.password, emailSet: emailSet, pendingEmailPattern: pendingEmailPattern, hasSecureValues: hasSecureValues))) controller?.dismiss() } })) } })) }, openDisablePassword: { - let presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 } - presentControllerImpl?(standardTextAlertController(theme: AlertControllerTheme(presentationTheme: presentationData.theme), title: nil, text: "Are you sure you want to disable your password?", actions: [TextAlertAction(type: .defaultAction, title: "Cancel", action: {}), TextAlertAction(type: .genericAction, title: "OK", action: { - var disablePassword = false - updateState { state in - if state.checking { - return state - } else { - disablePassword = true - return state.withUpdatedChecking(true) - } - } - if disablePassword { - setupDisposable.set((dataPromise.get() - |> take(1) - |> mapError { _ -> UpdateTwoStepVerificationPasswordError in return .generic } - |> mapToSignal { data -> Signal in - switch data { - case .access: - return .complete() - case let .manage(password, _, _): - return updateTwoStepVerificationPassword(network: account.network, currentPassword: password, updatedPassword: .none) - |> mapToSignal { _ -> Signal in + setupDisposable.set((dataPromise.get() |> take(1) |> deliverOnMainQueue).start(next: { data in + switch data { + case let .manage(_, _, _, hasSecureValues): + let presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 } + var text = presentationData.strings.TwoStepAuth_PasswordRemoveConfirmation + if hasSecureValues { + text = presentationData.strings.TwoStepAuth_PasswordRemovePassportConfirmation + } + presentControllerImpl?(standardTextAlertController(theme: AlertControllerTheme(presentationTheme: presentationData.theme), title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: { + var disablePassword = false + updateState { state in + if state.checking { + return state + } else { + disablePassword = true + return state.withUpdatedChecking(true) + } + } + if disablePassword { + setupDisposable.set((dataPromise.get() + |> take(1) + |> mapError { _ -> UpdateTwoStepVerificationPasswordError in return .generic } + |> mapToSignal { data -> Signal in + switch data { + case .access: return .complete() + case let .manage(password, _, _, _): + return updateTwoStepVerificationPassword(network: account.network, currentPassword: password, updatedPassword: .none) + |> mapToSignal { _ -> Signal in + return .complete() + } } + } + |> deliverOnMainQueue).start(error: { _ in + updateState { + $0.withUpdatedChecking(false) + } + }, completed: { + updateState { + $0.withUpdatedChecking(false) + } + dataPromise.set(.single(TwoStepVerificationUnlockSettingsControllerData.access(configuration: .notSet(pendingEmailPattern: "")))) + })) } - } - |> deliverOnMainQueue).start(error: { _ in - updateState { - $0.withUpdatedChecking(false) - } - }, completed: { - updateState { - $0.withUpdatedChecking(false) - } - dataPromise.set(.single(TwoStepVerificationUnlockSettingsControllerData.access(configuration: .notSet(pendingEmailPattern: "")))) - })) + })]), ViewControllerPresentationArguments(presentationAnimation: .modalSheet)) + default: + break } - })]), ViewControllerPresentationArguments(presentationAnimation: .modalSheet)) + })) }, openSetupEmail: { setupDisposable.set((dataPromise.get() |> take(1) |> deliverOnMainQueue).start(next: { data in switch data { case .access: break - case let .manage(password, _, _): + case let .manage(password, _, _, hasSecureValues): let result = Promise() let controller = twoStepVerificationPasswordEntryController(account: account, mode: .setupEmail(password: password), result: result) presentControllerImpl?(controller, ViewControllerPresentationArguments(presentationAnimation: .modalSheet)) setupResultDisposable.set((result.get() |> take(1) |> deliverOnMainQueue).start(next: { [weak controller] updatedPassword in if let updatedPassword = updatedPassword { - dataPromise.set(.single(TwoStepVerificationUnlockSettingsControllerData.manage(password: updatedPassword.password, emailSet: true, pendingEmailPattern: updatedPassword.pendingEmailPattern ?? ""))) + dataPromise.set(.single(TwoStepVerificationUnlockSettingsControllerData.manage(password: updatedPassword.password, emailSet: true, pendingEmailPattern: updatedPassword.pendingEmailPattern ?? "", hasSecureValues: hasSecureValues))) controller?.dismiss() } })) @@ -472,7 +483,7 @@ func twoStepVerificationUnlockSettingsController(account: Account, mode: TwoStep switch configuration { case .notSet: break - case .set: + case let .set(_, _, _, hasSecureValues): rightNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Common_Next), style: .bold, enabled: true, action: { var wasChecking = false var password: String? @@ -488,7 +499,7 @@ func twoStepVerificationUnlockSettingsController(account: Account, mode: TwoStep $0.withUpdatedChecking(false) } - replaceControllerImpl?(twoStepVerificationUnlockSettingsController(account: account, mode: .manage(password: password, email: settings.email, pendingEmailPattern: ""))) + replaceControllerImpl?(twoStepVerificationUnlockSettingsController(account: account, mode: .manage(password: password, email: settings.email, pendingEmailPattern: "", hasSecureValues: hasSecureValues))) }, error: { error in updateState { $0.withUpdatedChecking(false) @@ -506,7 +517,7 @@ func twoStepVerificationUnlockSettingsController(account: Account, mode: TwoStep text = presentationData.strings.Login_UnknownError } - presentControllerImpl?(standardTextAlertController(theme: AlertControllerTheme(presentationTheme: presentationData.theme), title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: "OK", action: {})]), ViewControllerPresentationArguments(presentationAnimation: .modalSheet)) + presentControllerImpl?(standardTextAlertController(theme: AlertControllerTheme(presentationTheme: presentationData.theme), title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), ViewControllerPresentationArguments(presentationAnimation: .modalSheet)) })) } })