From 5004405e0b1ae86baffebc3b285f6fe3a2fa43b5 Mon Sep 17 00:00:00 2001 From: Ali <> Date: Sat, 27 Nov 2021 00:04:30 +0400 Subject: [PATCH] Various improvements --- .../Telegram-iOS/en.lproj/Localizable.strings | 22 ++++++ .../Sources/AuthorizationOptionText.swift | 9 ++- submodules/CalendarMessageScreen/BUILD | 1 + .../Sources/CalendarMessageScreen.swift | 75 +++++++++++-------- .../Sources/ChatListController.swift | 48 ++++++++++++ .../Display/Source/DisplayLinkAnimator.swift | 4 +- .../TwoFactorAuthDataInputScreen.swift | 72 +++++++++--------- .../Sources/TwoFactorAuthSplashScreen.swift | 49 +++++++++--- .../PrivacyAndSecurityController.swift | 8 +- .../TwoStepVerificationUnlockController.swift | 2 +- .../TelegramCore/Sources/Authorization.swift | 20 +++-- .../TelegramNotices/Sources/Notices.swift | 22 ++++++ ...ationSequenceCodeEntryControllerNode.swift | 9 +-- .../AuthorizationSequenceController.swift | 17 ++++- .../TelegramUI/Sources/ChatController.swift | 9 +-- .../Sources/PeerInfo/PeerInfoScreen.swift | 2 +- 16 files changed, 262 insertions(+), 107 deletions(-) diff --git a/Telegram/Telegram-iOS/en.lproj/Localizable.strings b/Telegram/Telegram-iOS/en.lproj/Localizable.strings index b83fa6a26d..17fc15ba7c 100644 --- a/Telegram/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram/Telegram-iOS/en.lproj/Localizable.strings @@ -3765,6 +3765,7 @@ Unused sets are archived when you add more."; "AuthCode.Alert" = "Your login code is %@. Enter it in the Telegram app where you are trying to log in.\n\nDo not give this code to anyone."; "Login.CheckOtherSessionMessages" = "Check your Telegram messages"; "Login.SendCodeViaSms" = "Send the code as an SMS"; +"Login.SendCodeViaCall" = "Get code on my phone"; "Login.CancelPhoneVerification" = "Do you want to stop the phone number verification process?"; "Login.CancelPhoneVerificationStop" = "Stop"; "Login.CancelPhoneVerificationContinue" = "Continue"; @@ -7101,3 +7102,24 @@ Sorry for the inconvenience."; "AuthSessions.TerminateOtherSessionsText" = "Are you sure you want to terminate all other sessions?"; "Notifications.ResetAllNotificationsText" = "Are you sure you want to reset all notification settings to default?"; + +"MessageCalendar.ClearHistoryForThisDay" = "Clear History For This Day"; +"MessageCalendar.ClearHistoryForTheseDays" = "Clear History For These Days"; +"MessageCalendar.EmptySelectionTooltip" = "Please select one or more days first."; +"Chat.MessageRangeDeleted.ForMe_1" = "Messages for 1 day deleted."; +"Chat.MessageRangeDeleted.ForMe_any" = "Messages for %@ days deleted."; +"Chat.MessageRangeDeleted.ForBothSides_1" = "Messages for 1 day deleted for both sides."; +"Chat.MessageRangeDeleted.ForBothSides_any" = "Messages for %@ days deleted for both sides."; + +"ForcedPasswordSetup.Intro.Title" = "Set a Password"; +"ForcedPasswordSetup.Intro.Text" = "If you want to log into your account frequently, please choose a password."; +"ForcedPasswordSetup.Intro.Action" = "Set a Password"; +"ForcedPasswordSetup.Intro.DoneAction" = "Done"; +"ForcedPasswordSetup.Intro.DismissTitle" = "Warning"; +"ForcedPasswordSetup.Intro.DismissText_1" = "Proceed without a password? If you do not set a password, you will only be able to log into your account via SMS once every **day**."; +"ForcedPasswordSetup.Intro.DismissText_any" = "Proceed without a password? If you do not set a password, you will only be able to log into your account via SMS once every **%@ days**."; +"ForcedPasswordSetup.Intro.DismissActionCancel" = "No, let me set a password"; +"ForcedPasswordSetup.Intro.DismissActionOK" = "Yes, I’m sure"; + +"Login.CodePhonePatternInfoText" = "Please enter the last digits\nof the missed call number."; +"Login.EnterMissingDigits" = "Enter the missing digits"; diff --git a/submodules/AuthorizationUI/Sources/AuthorizationOptionText.swift b/submodules/AuthorizationUI/Sources/AuthorizationOptionText.swift index a3c8f2f70b..fe71055aef 100644 --- a/submodules/AuthorizationUI/Sources/AuthorizationOptionText.swift +++ b/submodules/AuthorizationUI/Sources/AuthorizationOptionText.swift @@ -45,7 +45,14 @@ public func authorizationNextOptionText(currentType: SentAuthorizationCodeType, } else { switch currentType { case .otherSession: - return (NSAttributedString(string: strings.Login_SendCodeViaSms, font: Font.regular(16.0), textColor: accentColor, paragraphAlignment: .center), true) + switch nextType { + case .sms: + return (NSAttributedString(string: strings.Login_SendCodeViaSms, font: Font.regular(16.0), textColor: accentColor, paragraphAlignment: .center), true) + case .call, .flashCall, .missedCall: + return (NSAttributedString(string: strings.Login_SendCodeViaCall, font: Font.regular(16.0), textColor: accentColor, paragraphAlignment: .center), true) + case .none: + return (NSAttributedString(string: strings.Login_HaveNotReceivedCodeInternal, font: Font.regular(16.0), textColor: accentColor, paragraphAlignment: .center), true) + } default: return (NSAttributedString(string: strings.Login_HaveNotReceivedCodeInternal, font: Font.regular(16.0), textColor: accentColor, paragraphAlignment: .center), true) } diff --git a/submodules/CalendarMessageScreen/BUILD b/submodules/CalendarMessageScreen/BUILD index 88c9da47b7..db198e2a0a 100644 --- a/submodules/CalendarMessageScreen/BUILD +++ b/submodules/CalendarMessageScreen/BUILD @@ -21,6 +21,7 @@ swift_library( "//submodules/PhotoResources:PhotoResources", "//submodules/DirectMediaImageCache:DirectMediaImageCache", "//submodules/TelegramStringFormatting:TelegramStringFormatting", + "//submodules/TooltipUI:TooltipUI", ], visibility = [ "//visibility:public", diff --git a/submodules/CalendarMessageScreen/Sources/CalendarMessageScreen.swift b/submodules/CalendarMessageScreen/Sources/CalendarMessageScreen.swift index 0f88c83891..9680abb33b 100644 --- a/submodules/CalendarMessageScreen/Sources/CalendarMessageScreen.swift +++ b/submodules/CalendarMessageScreen/Sources/CalendarMessageScreen.swift @@ -11,6 +11,7 @@ import ComponentFlow import PhotoResources import DirectMediaImageCache import TelegramStringFormatting +import TooltipUI private final class NullActionClass: NSObject, CAAction { @objc func run(forKey event: String, object anObject: Any, arguments dict: [AnyHashable : Any]?) { @@ -896,21 +897,20 @@ private final class MonthComponent: CombinedComponent { let dayEnvironment = context.environment[DayEnvironment.self].value let dayItemSize = updatedDays[0].size - let deltaWidth = floor((weekdayWidth - dayItemSize.width) / 2.0) - let deltaHeight = floor((weekdaySize - dayItemSize.width) / 2.0) + let selectionRadius: CGFloat = min(dayItemSize.width, dayItemSize.height) + + let deltaWidth = floor((weekdayWidth - selectionRadius) / 2.0) + let deltaHeight = floor((weekdaySize - selectionRadius) / 2.0) let minX = sideInset + CGFloat(selection.range.lowerBound) * weekdayWidth + deltaWidth let maxX = sideInset + CGFloat(selection.range.upperBound + 1) * weekdayWidth - deltaWidth let minY = baseDayY + CGFloat(lineIndex) * (weekdaySize + weekdaySpacing) + deltaHeight - let maxY = minY + dayItemSize.width - - let leftRadius: CGFloat = dayItemSize.width - let rightRadius: CGFloat = dayItemSize.width + let maxY = minY + selectionRadius let monthSelectionColor = context.component.theme.list.itemCheckColors.fillColor.withMultipliedAlpha(0.1) let selectionRect = CGRect(origin: CGPoint(x: minX, y: minY), size: CGSize(width: maxX - minX, height: maxY - minY)) let selection = selections[lineIndex].update( - component: AnyComponent(ImageComponent(image: dayEnvironment.imageCache.monthSelection(leftRadius: leftRadius, rightRadius: rightRadius, maxRadius: dayItemSize.width, color: monthSelectionColor))), + component: AnyComponent(ImageComponent(image: dayEnvironment.imageCache.monthSelection(leftRadius: selectionRadius, rightRadius: selectionRadius, maxRadius: selectionRadius, color: monthSelectionColor))), availableSize: selectionRect.size, transition: .immediate ) @@ -923,7 +923,7 @@ private final class MonthComponent: CombinedComponent { } let delay = Double(min(delayIndex, 6)) * 0.1 view.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.05, delay: delay) - view.layer.animateFrame(from: CGRect(origin: view.frame.origin, size: CGSize(width: leftRadius, height: view.frame.height)), to: view.frame, duration: 0.25, delay: delay, timingFunction: kCAMediaTimingFunctionSpring) + view.layer.animateFrame(from: CGRect(origin: view.frame.origin, size: CGSize(width: selectionRadius, height: view.frame.height)), to: view.frame, duration: 0.25, delay: delay, timingFunction: kCAMediaTimingFunctionSpring) }) .disappear(Transition.Disappear { view, transition, completion in if case .none = transition.animation { @@ -1314,37 +1314,36 @@ public final class CalendarMessageScreen: ViewController { if let selectionState = self.selectionState { let selectionToolbarNode: ToolbarNode - if let currrent = self.selectionToolbarNode { - selectionToolbarNode = currrent + let toolbarText: String + + var selectedCount = 0 + if let dayRange = selectionState.dayRange { + for i in 0 ..< self.months.count { + let firstDayTimestamp = Int32(self.months[i].firstDay.timeIntervalSince1970) - var selectedCount = 0 - if let dayRange = selectionState.dayRange { - for i in 0 ..< self.months.count { - let firstDayTimestamp = Int32(self.months[i].firstDay.timeIntervalSince1970) + for day in 0 ..< self.months[i].numberOfDays { + let dayTimestamp = firstDayTimestamp + 24 * 60 * 60 * Int32(day) - for day in 0 ..< self.months[i].numberOfDays { - let dayTimestamp = firstDayTimestamp + 24 * 60 * 60 * Int32(day) - - if dayRange.contains(dayTimestamp) { - selectedCount += 1 - } + if dayRange.contains(dayTimestamp) { + selectedCount += 1 } } } - - let toolbarText: String - if selectedCount == 0 { - toolbarText = self.presentationData.strings.DialogList_ClearHistoryConfirmation - } else if selectedCount == 1 { - //TODO:localize - toolbarText = "Clear History For This Day" - } else { - //TODO:localize - toolbarText = "Clear History For These Days" - } + } + + if selectedCount == 0 { + toolbarText = self.presentationData.strings.DialogList_ClearHistoryConfirmation + } else if selectedCount == 1 { + toolbarText = self.presentationData.strings.MessageCalendar_ClearHistoryForThisDay + } else { + toolbarText = self.presentationData.strings.MessageCalendar_ClearHistoryForTheseDays + } + + if let currrent = self.selectionToolbarNode { + selectionToolbarNode = currrent transition.updateFrame(node: selectionToolbarNode, frame: tabBarFrame) - selectionToolbarNode.updateLayout(size: tabBarFrame.size, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, additionalSideInsets: layout.additionalInsets, bottomInset: bottomInset, toolbar: Toolbar(leftAction: nil, rightAction: nil, middleAction: ToolbarAction(title: toolbarText, isEnabled: self.selectionState?.dayRange != nil, color: .custom(self.presentationData.theme.list.itemDestructiveColor))), transition: transition) + selectionToolbarNode.updateLayout(size: tabBarFrame.size, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, additionalSideInsets: layout.additionalInsets, bottomInset: bottomInset, toolbar: Toolbar(leftAction: nil, rightAction: nil, middleAction: ToolbarAction(title: toolbarText, isEnabled: true, color: .custom(self.selectionState?.dayRange != nil ? self.presentationData.theme.list.itemDestructiveColor : self.presentationData.theme.list.itemDisabledTextColor))), transition: transition) } else { selectionToolbarNode = ToolbarNode( theme: TabBarControllerTheme( @@ -1359,7 +1358,7 @@ public final class CalendarMessageScreen: ViewController { } ) selectionToolbarNode.frame = tabBarFrame - selectionToolbarNode.updateLayout(size: tabBarFrame.size, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, additionalSideInsets: layout.additionalInsets, bottomInset: bottomInset, toolbar: Toolbar(leftAction: nil, rightAction: nil, middleAction: ToolbarAction(title: self.presentationData.strings.DialogList_ClearHistoryConfirmation, isEnabled: self.selectionState?.dayRange != nil, color: .custom(self.presentationData.theme.list.itemDestructiveColor))), transition: .immediate) + selectionToolbarNode.updateLayout(size: tabBarFrame.size, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, additionalSideInsets: layout.additionalInsets, bottomInset: bottomInset, toolbar: Toolbar(leftAction: nil, rightAction: nil, middleAction: ToolbarAction(title: toolbarText, isEnabled: true, color: .custom(self.selectionState?.dayRange != nil ? self.presentationData.theme.list.itemDestructiveColor : self.presentationData.theme.list.itemDisabledTextColor))), transition: .immediate) self.addSubnode(selectionToolbarNode) self.selectionToolbarNode = selectionToolbarNode transition.animatePositionAdditive(node: selectionToolbarNode, offset: CGPoint(x: 0.0, y: tabBarFrame.height)) @@ -1425,6 +1424,16 @@ public final class CalendarMessageScreen: ViewController { } private func selectionToolbarActionSelected() { + if self.selectionState?.dayRange == nil { + if let selectionToolbarNode = self.selectionToolbarNode { + let toolbarFrame = selectionToolbarNode.view.convert(selectionToolbarNode.bounds, to: self.view) + self.controller?.present(TooltipScreen(account: self.context.account, text: self.presentationData.strings.MessageCalendar_EmptySelectionTooltip, style: .default, icon: .none, location: .point(toolbarFrame.insetBy(dx: 0.0, dy: 10.0), .bottom), shouldDismissOnTouch: { point in + return .dismiss(consume: false) + }), in: .current) + } + + return + } guard let selectionState = self.selectionState, let dayRange = selectionState.dayRange else { return } diff --git a/submodules/ChatListUI/Sources/ChatListController.swift b/submodules/ChatListUI/Sources/ChatListController.swift index da886e862e..1bdd92a0a9 100644 --- a/submodules/ChatListUI/Sources/ChatListController.swift +++ b/submodules/ChatListUI/Sources/ChatListController.swift @@ -24,6 +24,7 @@ import TelegramIntents import TooltipUI import TelegramCallsUI import StickerResources +import PasswordSetupUI private func fixListNodeScrolling(_ listNode: ListView, searchNode: NavigationBarSearchContentNode) -> Bool { if listNode.scroller.isDragging { @@ -1264,6 +1265,53 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController }) ], actionLayout: .vertical, parseMarkdown: true), in: .window(.root)) })) + + Queue.mainQueue().after(1.0, { + let _ = (self.context.account.postbox.transaction { transaction -> Int32? in + if let value = transaction.getNoticeEntry(key: ApplicationSpecificNotice.forcedPasswordSetupKey())?.get(ApplicationSpecificCounterNotice.self) { + return value.value + } else { + return nil + } + } + |> deliverOnMainQueue).start(next: { [weak self] value in + guard let strongSelf = self else { + return + } + + guard let value = value else { + return + } + + let controller = TwoFactorAuthSplashScreen(sharedContext: context.sharedContext, engine: .authorized(strongSelf.context.engine), mode: .intro(.init( + title: strongSelf.presentationData.strings.ForcedPasswordSetup_Intro_Title, + text: strongSelf.presentationData.strings.ForcedPasswordSetup_Intro_Text, + actionText: strongSelf.presentationData.strings.ForcedPasswordSetup_Intro_Action, + doneText: strongSelf.presentationData.strings.ForcedPasswordSetup_Intro_DoneAction + ))) + controller.dismissConfirmation = { [weak controller] f in + guard let strongSelf = self, let controller = controller else { + return true + } + + controller.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: strongSelf.presentationData), title: strongSelf.presentationData.strings.ForcedPasswordSetup_Intro_DismissTitle, text: strongSelf.presentationData.strings.ForcedPasswordSetup_Intro_DismissText(value), actions: [ + TextAlertAction(type: .genericAction, title: strongSelf.presentationData.strings.ForcedPasswordSetup_Intro_DismissActionCancel, action: { + }), + TextAlertAction(type: .destructiveAction, title: strongSelf.presentationData.strings.ForcedPasswordSetup_Intro_DismissActionOK, action: { [weak controller] in + if let strongSelf = self { + let _ = ApplicationSpecificNotice.setForcedPasswordSetup(postbox: strongSelf.context.account.postbox, reloginDaysTimeout: nil).start() + } + controller?.dismiss() + }) + ], parseMarkdown: true), in: .window(.root)) + + return false + } + strongSelf.push(controller) + + let _ = value + }) + }) } self.chatListDisplayNode.containerNode.addedVisibleChatsWithPeerIds = { [weak self] peerIds in diff --git a/submodules/Display/Source/DisplayLinkAnimator.swift b/submodules/Display/Source/DisplayLinkAnimator.swift index 2aa9fd0299..39759b6a9d 100644 --- a/submodules/Display/Source/DisplayLinkAnimator.swift +++ b/submodules/Display/Source/DisplayLinkAnimator.swift @@ -101,9 +101,9 @@ public final class ConstantDisplayLinkAnimator { self.displayLink = CADisplayLink(target: DisplayLinkTarget({ [weak self] in self?.tick() }), selector: #selector(DisplayLinkTarget.event)) - if #available(iOS 15.0, *) { + /*if #available(iOS 15.0, *) { self.displayLink?.preferredFrameRateRange = CAFrameRateRange(minimum: 60.0, maximum: 120.0, preferred: 120.0) - } + }*/ self.displayLink.isPaused = true self.displayLink.add(to: RunLoop.main, forMode: .common) } diff --git a/submodules/PasswordSetupUI/Sources/TwoFactorAuthDataInputScreen.swift b/submodules/PasswordSetupUI/Sources/TwoFactorAuthDataInputScreen.swift index ffd7790f00..02efd889cc 100644 --- a/submodules/PasswordSetupUI/Sources/TwoFactorAuthDataInputScreen.swift +++ b/submodules/PasswordSetupUI/Sources/TwoFactorAuthDataInputScreen.swift @@ -35,14 +35,14 @@ public enum TwoFactorDataInputMode { case authorized } - case password - case passwordRecoveryEmail(emailPattern: String, mode: PasswordRecoveryEmailMode) - case passwordRecovery(Recovery) - case emailAddress(password: String, hint: String) - case updateEmailAddress(password: String) - case emailConfirmation(passwordAndHint: (String, String)?, emailPattern: String, codeLength: Int?) - case passwordHint(recovery: Recovery?, password: String) - case rememberPassword + case password(doneText: String) + case passwordRecoveryEmail(emailPattern: String, mode: PasswordRecoveryEmailMode, doneText: String) + case passwordRecovery(recovery: Recovery, doneText: String) + case emailAddress(password: String, hint: String, doneText: String) + case updateEmailAddress(password: String, doneText: String) + case emailConfirmation(passwordAndHint: (String, String)?, emailPattern: String, codeLength: Int?, doneText: String) + case passwordHint(recovery: Recovery?, password: String, doneText: String) + case rememberPassword(doneText: String) } public final class TwoFactorDataInputScreen: ViewController { @@ -110,7 +110,7 @@ public final class TwoFactorDataInputScreen: ViewController { return } switch strongSelf.mode { - case .password: + case let .password(doneText): let values = (strongSelf.displayNode as! TwoFactorDataInputScreenNode).inputText if values.count != 2 { return @@ -136,9 +136,9 @@ public final class TwoFactorDataInputScreen: ViewController { } return true } - controllers.append(TwoFactorDataInputScreen(sharedContext: strongSelf.sharedContext, engine: strongSelf.engine, mode: .passwordHint(recovery: nil, password: values[0]), stateUpdated: strongSelf.stateUpdated, presentation: strongSelf.navigationPresentation)) + controllers.append(TwoFactorDataInputScreen(sharedContext: strongSelf.sharedContext, engine: strongSelf.engine, mode: .passwordHint(recovery: nil, password: values[0], doneText: doneText), stateUpdated: strongSelf.stateUpdated, presentation: strongSelf.navigationPresentation)) navigationController.setViewControllers(controllers, animated: true) - case let .passwordRecoveryEmail(_, mode): + case let .passwordRecoveryEmail(_, mode, doneText): guard let text = (strongSelf.displayNode as! TwoFactorDataInputScreenNode).inputText.first, !text.isEmpty else { return } @@ -180,14 +180,14 @@ public final class TwoFactorDataInputScreen: ViewController { mappedMode = .notAuthorized(syncContacts: syncContacts) } - let setupController = TwoFactorDataInputScreen(sharedContext: strongSelf.sharedContext, engine: strongSelf.engine, mode: .passwordRecovery(TwoFactorDataInputMode.Recovery(code: text, mode: mappedMode)), stateUpdated: strongSelf.stateUpdated, presentation: strongSelf.navigationPresentation) + let setupController = TwoFactorDataInputScreen(sharedContext: strongSelf.sharedContext, engine: strongSelf.engine, mode: .passwordRecovery(recovery: TwoFactorDataInputMode.Recovery(code: text, mode: mappedMode), doneText: doneText), stateUpdated: strongSelf.stateUpdated, presentation: strongSelf.navigationPresentation) guard let navigationController = strongSelf.navigationController as? NavigationController else { return } navigationController.replaceController(strongSelf, with: setupController, animated: true) })) - case let .passwordRecovery(recovery): + case let .passwordRecovery(recovery, doneText): let values = (strongSelf.displayNode as! TwoFactorDataInputScreenNode).inputText if values.count != 2 { return @@ -204,8 +204,8 @@ public final class TwoFactorDataInputScreen: ViewController { guard let navigationController = strongSelf.navigationController as? NavigationController else { return } - navigationController.replaceController(strongSelf, with: TwoFactorDataInputScreen(sharedContext: strongSelf.sharedContext, engine: strongSelf.engine, mode: .passwordHint(recovery: recovery, password: values[0]), stateUpdated: strongSelf.stateUpdated, presentation: strongSelf.navigationPresentation), animated: true) - case let .emailAddress(password, hint): + navigationController.replaceController(strongSelf, with: TwoFactorDataInputScreen(sharedContext: strongSelf.sharedContext, engine: strongSelf.engine, mode: .passwordHint(recovery: recovery, password: values[0], doneText: doneText), stateUpdated: strongSelf.stateUpdated, presentation: strongSelf.navigationPresentation), animated: true) + case let .emailAddress(password, hint, doneText): guard let text = (strongSelf.displayNode as! TwoFactorDataInputScreenNode).inputText.first, !text.isEmpty else { return } @@ -237,7 +237,7 @@ public final class TwoFactorDataInputScreen: ViewController { } return true } - controllers.append(TwoFactorDataInputScreen(sharedContext: strongSelf.sharedContext, engine: strongSelf.engine, mode: .emailConfirmation(passwordAndHint: (password, hint), emailPattern: text, codeLength: pendingEmail.codeLength.flatMap(Int.init)), stateUpdated: strongSelf.stateUpdated, presentation: strongSelf.navigationPresentation)) + controllers.append(TwoFactorDataInputScreen(sharedContext: strongSelf.sharedContext, engine: strongSelf.engine, mode: .emailConfirmation(passwordAndHint: (password, hint), emailPattern: text, codeLength: pendingEmail.codeLength.flatMap(Int.init), doneText: doneText), stateUpdated: strongSelf.stateUpdated, presentation: strongSelf.navigationPresentation)) navigationController.setViewControllers(controllers, animated: true) } else { guard let navigationController = strongSelf.navigationController as? NavigationController else { @@ -252,7 +252,7 @@ public final class TwoFactorDataInputScreen: ViewController { } return true } - controllers.append(TwoFactorAuthSplashScreen(sharedContext: strongSelf.sharedContext, engine: strongSelf.engine, mode: .done)) + controllers.append(TwoFactorAuthSplashScreen(sharedContext: strongSelf.sharedContext, engine: strongSelf.engine, mode: .done(doneText: doneText))) navigationController.setViewControllers(controllers, animated: true) } } @@ -273,7 +273,7 @@ public final class TwoFactorDataInputScreen: ViewController { } strongSelf.present(textAlertController(sharedContext: strongSelf.sharedContext, title: nil, text: alertText, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root)) }) - case let .updateEmailAddress(password): + case let .updateEmailAddress(password, doneText): guard let text = (strongSelf.displayNode as! TwoFactorDataInputScreenNode).inputText.first, !text.isEmpty else { return } @@ -307,7 +307,7 @@ public final class TwoFactorDataInputScreen: ViewController { } return true } - controllers.append(TwoFactorDataInputScreen(sharedContext: strongSelf.sharedContext, engine: strongSelf.engine, mode: .emailConfirmation(passwordAndHint: (password, ""), emailPattern: text, codeLength: pendingEmail.codeLength.flatMap(Int.init)), stateUpdated: strongSelf.stateUpdated)) + controllers.append(TwoFactorDataInputScreen(sharedContext: strongSelf.sharedContext, engine: strongSelf.engine, mode: .emailConfirmation(passwordAndHint: (password, ""), emailPattern: text, codeLength: pendingEmail.codeLength.flatMap(Int.init), doneText: doneText), stateUpdated: strongSelf.stateUpdated)) navigationController.setViewControllers(controllers, animated: true) } else { guard let navigationController = strongSelf.navigationController as? NavigationController else { @@ -322,7 +322,7 @@ public final class TwoFactorDataInputScreen: ViewController { } return true } - controllers.append(TwoFactorAuthSplashScreen(sharedContext: strongSelf.sharedContext, engine: strongSelf.engine, mode: .done)) + controllers.append(TwoFactorAuthSplashScreen(sharedContext: strongSelf.sharedContext, engine: strongSelf.engine, mode: .done(doneText: doneText))) navigationController.setViewControllers(controllers, animated: true) } } @@ -346,7 +346,7 @@ public final class TwoFactorDataInputScreen: ViewController { case .unauthorized: break } - case .emailConfirmation: + case let .emailConfirmation(_, _, _, doneText): guard let text = (strongSelf.displayNode as! TwoFactorDataInputScreenNode).inputText.first, !text.isEmpty else { return } @@ -397,13 +397,13 @@ public final class TwoFactorDataInputScreen: ViewController { } return true } - controllers.append(TwoFactorAuthSplashScreen(sharedContext: strongSelf.sharedContext, engine: strongSelf.engine, mode: .done)) + controllers.append(TwoFactorAuthSplashScreen(sharedContext: strongSelf.sharedContext, engine: strongSelf.engine, mode: .done(doneText: doneText))) navigationController.setViewControllers(controllers, animated: true) }) case .unauthorized: break } - case let .passwordHint(recovery, password): + case let .passwordHint(recovery, password, doneText): guard let value = (strongSelf.displayNode as! TwoFactorDataInputScreenNode).inputText.first, !value.isEmpty else { return } @@ -411,7 +411,7 @@ public final class TwoFactorDataInputScreen: ViewController { if let recovery = recovery { strongSelf.performRecovery(recovery: recovery, password: password, hint: value) } else { - strongSelf.push(TwoFactorDataInputScreen(sharedContext: strongSelf.sharedContext, engine: strongSelf.engine, mode: .emailAddress(password: password, hint: value), stateUpdated: strongSelf.stateUpdated, presentation: strongSelf.navigationPresentation)) + strongSelf.push(TwoFactorDataInputScreen(sharedContext: strongSelf.sharedContext, engine: strongSelf.engine, mode: .emailAddress(password: password, hint: value, doneText: doneText), stateUpdated: strongSelf.stateUpdated, presentation: strongSelf.navigationPresentation)) } case .rememberPassword: guard case let .authorized(engine) = strongSelf.engine else { @@ -476,7 +476,7 @@ public final class TwoFactorDataInputScreen: ViewController { return } switch strongSelf.mode { - case let .emailAddress(password, hint): + case let .emailAddress(password, hint, doneText): strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: strongSelf.presentationData), title: strongSelf.presentationData.strings.TwoFactorSetup_Email_SkipConfirmationTitle, text: strongSelf.presentationData.strings.TwoFactorSetup_Email_SkipConfirmationText, actions: [ TextAlertAction(type: .destructiveAction, title: strongSelf.presentationData.strings.TwoFactorSetup_Email_SkipConfirmationSkip, action: { guard let strongSelf = self else { @@ -509,7 +509,7 @@ public final class TwoFactorDataInputScreen: ViewController { } return true } - controllers.append(TwoFactorAuthSplashScreen(sharedContext: strongSelf.sharedContext, engine: strongSelf.engine, mode: .done)) + controllers.append(TwoFactorAuthSplashScreen(sharedContext: strongSelf.sharedContext, engine: strongSelf.engine, mode: .done(doneText: doneText))) navigationController.setViewControllers(controllers, animated: true) } }, error: { [weak statusController] error in @@ -532,13 +532,13 @@ public final class TwoFactorDataInputScreen: ViewController { }), TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_Cancel, action: {}) ]), in: .window(.root)) - case let .passwordHint(recovery, password): + case let .passwordHint(recovery, password, doneText): if let recovery = recovery { strongSelf.performRecovery(recovery: recovery, password: password, hint: "") } else { - strongSelf.push(TwoFactorDataInputScreen(sharedContext: strongSelf.sharedContext, engine: strongSelf.engine, mode: .emailAddress(password: password, hint: ""), stateUpdated: strongSelf.stateUpdated, presentation: strongSelf.navigationPresentation)) + strongSelf.push(TwoFactorDataInputScreen(sharedContext: strongSelf.sharedContext, engine: strongSelf.engine, mode: .emailAddress(password: password, hint: "", doneText: doneText), stateUpdated: strongSelf.stateUpdated, presentation: strongSelf.navigationPresentation)) } - case let .passwordRecovery(recovery): + case let .passwordRecovery(recovery, _): strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: strongSelf.presentationData), title: strongSelf.presentationData.strings.TwoFactorSetup_PasswordRecovery_SkipAlertTitle, text: strongSelf.presentationData.strings.TwoFactorSetup_PasswordRecovery_SkipAlertText, actions: [ TextAlertAction(type: .destructiveAction, title: strongSelf.presentationData.strings.TwoFactorSetup_PasswordRecovery_SkipAlertAction, action: { guard let strongSelf = self else { @@ -548,7 +548,7 @@ public final class TwoFactorDataInputScreen: ViewController { }), TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_Cancel, action: {}) ]), in: .window(.root)) - case .rememberPassword: + case let .rememberPassword(doneText): guard case let .authorized(engine) = strongSelf.engine else { return } @@ -575,7 +575,7 @@ public final class TwoFactorDataInputScreen: ViewController { disposable.set((engine.auth.requestTwoStepVerificationPasswordRecoveryCode() |> deliverOnMainQueue).start(next: { emailPattern in var stateUpdated: ((SetupTwoStepVerificationStateUpdate) -> Void)? - let controller = TwoFactorDataInputScreen(sharedContext: sharedContext, engine: .authorized(engine), mode: .passwordRecoveryEmail(emailPattern: emailPattern, mode: .authorized), stateUpdated: { state in + let controller = TwoFactorDataInputScreen(sharedContext: sharedContext, engine: .authorized(engine), mode: .passwordRecoveryEmail(emailPattern: emailPattern, mode: .authorized, doneText: doneText), stateUpdated: { state in stateUpdated?(state) }) stateUpdated = { [weak controller] state in @@ -706,7 +706,7 @@ public final class TwoFactorDataInputScreen: ViewController { return } switch strongSelf.mode { - case let .emailConfirmation(passwordAndHint, _, _): + case let .emailConfirmation(passwordAndHint, _, _, doneText): if let (password, hint) = passwordAndHint { guard let navigationController = strongSelf.navigationController as? NavigationController else { return @@ -720,7 +720,7 @@ public final class TwoFactorDataInputScreen: ViewController { } return true } - controllers.append(TwoFactorDataInputScreen(sharedContext: strongSelf.sharedContext, engine: strongSelf.engine, mode: .emailAddress(password: password, hint: hint), stateUpdated: strongSelf.stateUpdated, presentation: strongSelf.navigationPresentation)) + controllers.append(TwoFactorDataInputScreen(sharedContext: strongSelf.sharedContext, engine: strongSelf.engine, mode: .emailAddress(password: password, hint: hint, doneText: doneText), stateUpdated: strongSelf.stateUpdated, presentation: strongSelf.navigationPresentation)) navigationController.setViewControllers(controllers, animated: true) } else { } @@ -1371,7 +1371,7 @@ private final class TwoFactorDataInputScreenNode: ViewControllerTracingNode, UIS toggleTextHidden?(node) }), ] - case let .passwordRecoveryEmail(emailPattern, _): + case let .passwordRecoveryEmail(emailPattern, _, _): title = presentationData.strings.TwoFactorSetup_EmailVerification_Title let formattedString = presentationData.strings.TwoFactorSetup_EmailVerification_Text(emailPattern) @@ -1398,7 +1398,7 @@ private final class TwoFactorDataInputScreenNode: ViewControllerTracingNode, UIS toggleTextHidden?(node) }), ] - case let .emailConfirmation(_, emailPattern, _): + case let .emailConfirmation(_, emailPattern, _, _): title = presentationData.strings.TwoFactorSetup_EmailVerification_Title let formattedString = presentationData.strings.TwoFactorSetup_EmailVerification_Text(emailPattern) @@ -1654,7 +1654,7 @@ private final class TwoFactorDataInputScreenNode: ViewControllerTracingNode, UIS strongSelf.buttonNode.isHidden = !hasText strongSelf.skipActionTitleNode.isHidden = hasText strongSelf.skipActionButtonNode.isHidden = hasText - case let .emailConfirmation(_, _, codeLength): + case let .emailConfirmation(_, _, codeLength, _): let text = strongSelf.inputNodes[0].text let hasText = !text.isEmpty strongSelf.buttonNode.isHidden = !hasText diff --git a/submodules/PasswordSetupUI/Sources/TwoFactorAuthSplashScreen.swift b/submodules/PasswordSetupUI/Sources/TwoFactorAuthSplashScreen.swift index 968092fea7..a3b5cc982f 100644 --- a/submodules/PasswordSetupUI/Sources/TwoFactorAuthSplashScreen.swift +++ b/submodules/PasswordSetupUI/Sources/TwoFactorAuthSplashScreen.swift @@ -13,8 +13,27 @@ import PresentationDataUtils import TelegramCore public enum TwoFactorAuthSplashMode { - case intro - case done + public struct Intro { + public var title: String + public var text: String + public var actionText: String + public var doneText: String + + public init( + title: String, + text: String, + actionText: String, + doneText: String + ) { + self.title = title + self.text = text + self.actionText = actionText + self.doneText = doneText + } + } + + case intro(Intro) + case done(doneText: String) case recoveryDone(recoveredAccountData: RecoveredAccountData?, syncContacts: Bool, isPasswordSet: Bool) case remember } @@ -25,6 +44,8 @@ public final class TwoFactorAuthSplashScreen: ViewController { private var presentationData: PresentationData private var mode: TwoFactorAuthSplashMode + public var dismissConfirmation: ((@escaping () -> Void) -> Bool)? + public init(sharedContext: SharedAccountContext, engine: SomeTelegramEngine, mode: TwoFactorAuthSplashMode, presentation: ViewControllerNavigationPresentation = .modalInLargeLayout) { self.sharedContext = sharedContext self.engine = engine @@ -55,6 +76,14 @@ public final class TwoFactorAuthSplashScreen: ViewController { } else { self.navigationItem.leftBarButtonItem = UIBarButtonItem(customDisplayNode: ASDisplayNode()) } + + self.attemptNavigation = { [weak self] f in + guard let strongSelf = self, let dismissConfirmation = strongSelf.dismissConfirmation else { + return true + } + + return dismissConfirmation(f) + } } required init(coder aDecoder: NSCoder) { @@ -70,8 +99,8 @@ public final class TwoFactorAuthSplashScreen: ViewController { return } switch strongSelf.mode { - case .intro: - strongSelf.push(TwoFactorDataInputScreen(sharedContext: strongSelf.sharedContext, engine: strongSelf.engine, mode: .password, stateUpdated: { _ in + case let .intro(intro): + strongSelf.push(TwoFactorDataInputScreen(sharedContext: strongSelf.sharedContext, engine: strongSelf.engine, mode: .password(doneText: intro.doneText), stateUpdated: { _ in }, presentation: strongSelf.navigationPresentation)) case .done, .remember: guard let navigationController = strongSelf.navigationController as? NavigationController else { @@ -136,18 +165,18 @@ private final class TwoFactorAuthSplashScreenNode: ViewControllerTracingNode { let textColor = self.presentationData.theme.list.itemPrimaryTextColor switch mode { - case .intro: - title = self.presentationData.strings.TwoFactorSetup_Intro_Title - texts = [NSAttributedString(string: self.presentationData.strings.TwoFactorSetup_Intro_Text, font: textFont, textColor: textColor)] - buttonText = self.presentationData.strings.TwoFactorSetup_Intro_Action + case let .intro(intro): + title = intro.title + texts = [NSAttributedString(string: intro.text, font: textFont, textColor: textColor)] + buttonText = intro.actionText self.animationNode.setup(source: AnimatedStickerNodeLocalFileSource(name: "TwoFactorSetupIntro"), width: 248, height: 248, playbackMode: .once, mode: .direct(cachePathPrefix: nil)) self.animationSize = CGSize(width: 124.0, height: 124.0) self.animationNode.visibility = true - case .done: + case let .done(doneText): title = self.presentationData.strings.TwoFactorSetup_Done_Title texts = [NSAttributedString(string: self.presentationData.strings.TwoFactorSetup_Done_Text, font: textFont, textColor: textColor)] - buttonText = self.presentationData.strings.TwoFactorSetup_Done_Action + buttonText = doneText self.animationNode.setup(source: AnimatedStickerNodeLocalFileSource(name: "TwoFactorSetupDone"), width: 248, height: 248, mode: .direct(cachePathPrefix: nil)) self.animationSize = CGSize(width: 124.0, height: 124.0) diff --git a/submodules/SettingsUI/Sources/Privacy and Security/PrivacyAndSecurityController.swift b/submodules/SettingsUI/Sources/Privacy and Security/PrivacyAndSecurityController.swift index 0e814c733f..bfa6b090ea 100644 --- a/submodules/SettingsUI/Sources/Privacy and Security/PrivacyAndSecurityController.swift +++ b/submodules/SettingsUI/Sources/Privacy and Security/PrivacyAndSecurityController.swift @@ -732,7 +732,13 @@ public func privacyAndSecurityController(context: AccountContext, initialSetting break case let .notSet(pendingEmail): if pendingEmail == nil { - let controller = TwoFactorAuthSplashScreen(sharedContext: context.sharedContext, engine: .authorized(context.engine), mode: .intro) + let presentationData = context.sharedContext.currentPresentationData.with { $0 } + let controller = TwoFactorAuthSplashScreen(sharedContext: context.sharedContext, engine: .authorized(context.engine), mode: .intro(.init( + title: presentationData.strings.TwoFactorSetup_Intro_Title, + text: presentationData.strings.TwoFactorSetup_Intro_Text, + actionText: presentationData.strings.TwoFactorSetup_Intro_Action, + doneText: presentationData.strings.TwoFactorSetup_Done_Action + ))) pushControllerImpl?(controller, true) return diff --git a/submodules/SettingsUI/Sources/Privacy and Security/TwoStepVerificationUnlockController.swift b/submodules/SettingsUI/Sources/Privacy and Security/TwoStepVerificationUnlockController.swift index aad0182437..4ab4a52ad1 100644 --- a/submodules/SettingsUI/Sources/Privacy and Security/TwoStepVerificationUnlockController.swift +++ b/submodules/SettingsUI/Sources/Privacy and Security/TwoStepVerificationUnlockController.swift @@ -509,7 +509,7 @@ public func twoStepVerificationUnlockSettingsController(context: AccountContext, } var stateUpdated: ((SetupTwoStepVerificationStateUpdate) -> Void)? - let controller = TwoFactorDataInputScreen(sharedContext: context.sharedContext, engine: .authorized(context.engine), mode: .passwordRecoveryEmail(emailPattern: emailPattern, mode: .authorized), stateUpdated: { state in + let controller = TwoFactorDataInputScreen(sharedContext: context.sharedContext, engine: .authorized(context.engine), mode: .passwordRecoveryEmail(emailPattern: emailPattern, mode: .authorized, doneText: presentationData.strings.TwoFactorSetup_Done_Action), stateUpdated: { state in stateUpdated?(state) }) stateUpdated = { [weak controller] state in diff --git a/submodules/TelegramCore/Sources/Authorization.swift b/submodules/TelegramCore/Sources/Authorization.swift index 9ba35f0361..6624cbd1c0 100644 --- a/submodules/TelegramCore/Sources/Authorization.swift +++ b/submodules/TelegramCore/Sources/Authorization.swift @@ -105,11 +105,11 @@ public func sendAuthorizationCode(accountManager: AccountManager `catch` { error -> Signal<(SendCodeResult, UnauthorizedAccount), MTRpcError> in if error.errorDescription == "SESSION_PASSWORD_NEEDED" { - return account.network.request(Api.functions.account.getPassword(), automaticFloodWait: false) + return updatedAccount.network.request(Api.functions.account.getPassword(), automaticFloodWait: false) |> mapToSignal { result -> Signal<(SendCodeResult, UnauthorizedAccount), MTRpcError> in switch result { case let .password(_, _, _, _, hint, _, _, _, _, _): - return .single((.password(hint: hint), account)) + return .single((.password(hint: hint), updatedAccount)) } } } else { @@ -252,7 +252,7 @@ public enum AuthorizeWithCodeResult { case loggedIn } -public func authorizeWithCode(accountManager: AccountManager, account: UnauthorizedAccount, code: String, termsOfService: UnauthorizedAccountTermsOfService?) -> Signal { +public func authorizeWithCode(accountManager: AccountManager, account: UnauthorizedAccount, code: String, termsOfService: UnauthorizedAccountTermsOfService?, forcedPasswordSetupNotice: @escaping (Int32) -> (NoticeEntryKey, CodableEntry)?) -> Signal { return account.postbox.transaction { transaction -> Signal in if let state = transaction.getState() as? UnauthorizedAccountState { switch state.contents { @@ -302,11 +302,14 @@ public func authorizeWithCode(accountManager: AccountManager AuthorizeWithCodeResult in switchToAuthorizedAccount(transaction: transaction, account: account) return .loggedIn @@ -542,7 +545,7 @@ public enum SignUpError { case invalidLastName } -public func signUpWithName(accountManager: AccountManager, account: UnauthorizedAccount, firstName: String, lastName: String, avatarData: Data?, avatarVideo: Signal?, videoStartTimestamp: Double?) -> Signal { +public func signUpWithName(accountManager: AccountManager, account: UnauthorizedAccount, firstName: String, lastName: String, avatarData: Data?, avatarVideo: Signal?, videoStartTimestamp: Double?, forcedPasswordSetupNotice: @escaping (Int32) -> (NoticeEntryKey, CodableEntry)?) -> Signal { return account.postbox.transaction { transaction -> Signal in if let state = transaction.getState() as? UnauthorizedAccountState, case let .signUp(number, codeHash, _, _, _, syncContacts) = state.contents { return account.network.request(Api.functions.auth.signUp(phoneNumber: number, phoneCodeHash: codeHash, firstName: firstName, lastName: lastName)) @@ -561,7 +564,7 @@ public func signUpWithName(accountManager: AccountManager mapToSignal { result -> Signal in switch result { - case let .authorization(_, _, _, user): + case let .authorization(_, otherwiseReloginDays, _, user): let user = TelegramUser(user: user) let appliedState = account.postbox.transaction { transaction -> Void in let state = AuthorizedAccountState(isTestingEnvironment: account.testingEnvironment, masterDatacenterId: account.masterDatacenterId, peerId: user.id, state: nil) @@ -570,8 +573,11 @@ public func signUpWithName(accountManager: AccountManager castError(SignUpError.self) + } + |> castError(SignUpError.self) let switchedAccounts = accountManager.transaction { transaction -> Void in switchToAuthorizedAccount(transaction: transaction, account: account) diff --git a/submodules/TelegramNotices/Sources/Notices.swift b/submodules/TelegramNotices/Sources/Notices.swift index 3c3e3f247d..7f247ce276 100644 --- a/submodules/TelegramNotices/Sources/Notices.swift +++ b/submodules/TelegramNotices/Sources/Notices.swift @@ -162,6 +162,7 @@ private enum ApplicationSpecificGlobalNotice: Int32 { case interactiveEmojiSyncTip = 28 case sharedMediaScrollingTooltip = 29 case sharedMediaFastScrollingTooltip = 30 + case forcedPasswordSetup = 31 var key: ValueBoxKey { let v = ValueBoxKey(length: 4) @@ -211,6 +212,10 @@ private struct ApplicationSpecificNoticeKeys { return NoticeEntryKey(namespace: noticeNamespace(namespace: peerReportNamespace), key: noticeKey(peerId: peerId, key: 0)) } + static func forcedPasswordSetup() -> NoticeEntryKey { + return NoticeEntryKey(namespace: noticeNamespace(namespace: globalNamespace), key: ApplicationSpecificGlobalNotice.secretChatInlineBotUsage.key) + } + static func secretChatInlineBotUsage() -> NoticeEntryKey { return NoticeEntryKey(namespace: noticeNamespace(namespace: globalNamespace), key: ApplicationSpecificGlobalNotice.secretChatInlineBotUsage.key) } @@ -1098,6 +1103,23 @@ public struct ApplicationSpecificNotice { } } + public static func forcedPasswordSetupKey() -> NoticeEntryKey { + return ApplicationSpecificNoticeKeys.forcedPasswordSetup() + } + + public static func setForcedPasswordSetup(postbox: Postbox, reloginDaysTimeout: Int32?) -> Signal { + return postbox.transaction { transaction -> Void in + if let reloginDaysTimeout = reloginDaysTimeout { + if let entry = CodableEntry(ApplicationSpecificCounterNotice(value: reloginDaysTimeout)) { + transaction.setNoticeEntry(key: ApplicationSpecificNoticeKeys.forcedPasswordSetup(), value: entry) + } + } else { + transaction.setNoticeEntry(key: ApplicationSpecificNoticeKeys.forcedPasswordSetup(), value: nil) + } + } + |> ignoreValues + } + public static func reset(accountManager: AccountManager) -> Signal { return accountManager.transaction { transaction -> Void in } diff --git a/submodules/TelegramUI/Sources/AuthorizationSequenceCodeEntryControllerNode.swift b/submodules/TelegramUI/Sources/AuthorizationSequenceCodeEntryControllerNode.swift index 663247d7fe..698aa9262f 100644 --- a/submodules/TelegramUI/Sources/AuthorizationSequenceCodeEntryControllerNode.swift +++ b/submodules/TelegramUI/Sources/AuthorizationSequenceCodeEntryControllerNode.swift @@ -177,8 +177,7 @@ final class AuthorizationSequenceCodeEntryControllerNode: ASDisplayNode, UITextF self.currentOptionNode.attributedText = authorizationCurrentOptionText(codeType, strings: self.strings, primaryColor: self.theme.list.itemPrimaryTextColor, accentColor: self.theme.list.itemAccentColor) if case .missedCall = codeType { - //TODO:localize - self.currentOptionInfoNode.attributedText = NSAttributedString(string: "Please enter the last five digits\nof the missed call number.", font: Font.regular(16.0), textColor: self.theme.list.itemPrimaryTextColor, paragraphAlignment: .center) + self.currentOptionInfoNode.attributedText = NSAttributedString(string: self.strings.Login_CodePhonePatternInfoText, font: Font.regular(16.0), textColor: self.theme.list.itemPrimaryTextColor, paragraphAlignment: .center) } else { self.currentOptionInfoNode.attributedText = NSAttributedString(string: "", font: Font.regular(15.0), textColor: self.theme.list.itemPrimaryTextColor) } @@ -227,8 +226,7 @@ final class AuthorizationSequenceCodeEntryControllerNode: ASDisplayNode, UITextF case .otherSession: self.titleNode.attributedText = NSAttributedString(string: self.strings.Login_CheckOtherSessionMessages, font: Font.medium(32.0), textColor: self.theme.list.itemPrimaryTextColor) case .missedCall: - //TODO:localize - self.titleNode.attributedText = NSAttributedString(string: "Enter the missing digits", font: Font.medium(32.0), textColor: self.theme.list.itemPrimaryTextColor) + self.titleNode.attributedText = NSAttributedString(string: self.strings.Login_EnterMissingDigits, font: Font.medium(32.0), textColor: self.theme.list.itemPrimaryTextColor) default: self.titleNode.attributedText = NSAttributedString(string: self.phoneNumber, font: Font.light(40.0), textColor: self.theme.list.itemPrimaryTextColor) } @@ -253,8 +251,7 @@ final class AuthorizationSequenceCodeEntryControllerNode: ASDisplayNode, UITextF } else { fontSize = 18.0 } - //TODO:localize - self.titleNode.attributedText = NSAttributedString(string: "Enter the missing digits", font: Font.semibold(fontSize), textColor: self.theme.list.itemPrimaryTextColor) + self.titleNode.attributedText = NSAttributedString(string: self.strings.Login_EnterMissingDigits, font: Font.semibold(fontSize), textColor: self.theme.list.itemPrimaryTextColor) default: self.titleNode.attributedText = NSAttributedString(string: self.phoneNumber, font: Font.light(30.0), textColor: self.theme.list.itemPrimaryTextColor) } diff --git a/submodules/TelegramUI/Sources/AuthorizationSequenceController.swift b/submodules/TelegramUI/Sources/AuthorizationSequenceController.swift index 2a0b71c431..a8f4256365 100644 --- a/submodules/TelegramUI/Sources/AuthorizationSequenceController.swift +++ b/submodules/TelegramUI/Sources/AuthorizationSequenceController.swift @@ -17,6 +17,7 @@ import PhoneNumberFormat import LegacyComponents import LegacyMediaPickerUI import PasswordSetupUI +import TelegramNotices private enum InnerState: Equatable { case state(UnauthorizedAccountStateContents) @@ -289,7 +290,12 @@ public final class AuthorizationSequenceController: NavigationController, MFMail if let strongSelf = self { controller?.inProgress = true - strongSelf.actionDisposable.set((authorizeWithCode(accountManager: strongSelf.sharedContext.accountManager, account: strongSelf.account, code: code, termsOfService: termsOfService?.0) + strongSelf.actionDisposable.set((authorizeWithCode(accountManager: strongSelf.sharedContext.accountManager, account: strongSelf.account, code: code, termsOfService: termsOfService?.0, forcedPasswordSetupNotice: { value in + guard let entry = CodableEntry(ApplicationSpecificCounterNotice(value: value)) else { + return nil + } + return (ApplicationSpecificNotice.forcedPasswordSetupKey(), entry) + }) |> deliverOnMainQueue).start(next: { result in guard let strongSelf = self else { return @@ -553,7 +559,7 @@ public final class AuthorizationSequenceController: NavigationController, MFMail if let currentController = currentController { controller = currentController } else { - controller = TwoFactorDataInputScreen(sharedContext: self.sharedContext, engine: .unauthorized(TelegramEngineUnauthorized(account: self.account)), mode: .passwordRecoveryEmail(emailPattern: emailPattern, mode: .notAuthorized(syncContacts: syncContacts)), stateUpdated: { _ in + controller = TwoFactorDataInputScreen(sharedContext: self.sharedContext, engine: .unauthorized(TelegramEngineUnauthorized(account: self.account)), mode: .passwordRecoveryEmail(emailPattern: emailPattern, mode: .notAuthorized(syncContacts: syncContacts), doneText: self.presentationData.strings.TwoFactorSetup_Done_Action), stateUpdated: { _ in }, presentation: .default) } controller.passwordRecoveryFailed = { [weak self] in @@ -713,7 +719,12 @@ public final class AuthorizationSequenceController: NavigationController, MFMail avatarVideo = nil } - strongSelf.actionDisposable.set((signUpWithName(accountManager: strongSelf.sharedContext.accountManager, account: strongSelf.account, firstName: firstName, lastName: lastName, avatarData: avatarData, avatarVideo: avatarVideo, videoStartTimestamp: videoStartTimestamp) + strongSelf.actionDisposable.set((signUpWithName(accountManager: strongSelf.sharedContext.accountManager, account: strongSelf.account, firstName: firstName, lastName: lastName, avatarData: avatarData, avatarVideo: avatarVideo, videoStartTimestamp: videoStartTimestamp, forcedPasswordSetupNotice: { value in + guard let entry = CodableEntry(ApplicationSpecificCounterNotice(value: value)) else { + return nil + } + return (ApplicationSpecificNotice.forcedPasswordSetupKey(), entry) + }) |> deliverOnMainQueue).start(error: { error in Queue.mainQueue().async { if let strongSelf = self, let controller = controller { diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index a5506c31aa..17c2d3ea29 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -11864,16 +11864,13 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G return } - //TODO:localize - var statusText: String - statusText = "Messages for \(dayCount) \(dayCount == 1 ? "day" : "days") deleted" + let statusText: String switch type { case .forEveryone: - statusText += " for both sides" + statusText = strongSelf.presentationData.strings.Chat_MessageRangeDeleted_ForBothSides(Int32(dayCount)) default: - break + statusText = strongSelf.presentationData.strings.Chat_MessageRangeDeleted_ForMe(Int32(dayCount)) } - statusText += "." strongSelf.chatDisplayNode.historyNode.ignoreMessagesInTimestampRange = range diff --git a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift index 04fa0b309a..2a0a93a01b 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift @@ -5496,7 +5496,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate } case .rememberPassword: let context = self.context - let controller = TwoFactorDataInputScreen(sharedContext: self.context.sharedContext, engine: .authorized(self.context.engine), mode: .rememberPassword, stateUpdated: { _ in + let controller = TwoFactorDataInputScreen(sharedContext: self.context.sharedContext, engine: .authorized(self.context.engine), mode: .rememberPassword(doneText: self.presentationData.strings.TwoFactorSetup_Done_Action), stateUpdated: { _ in }, presentation: .modalInLargeLayout) controller.twoStepAuthSettingsController = { configuration in return twoStepVerificationUnlockSettingsController(context: context, mode: .access(intro: false, data: .single(TwoStepVerificationUnlockSettingsControllerData.access(configuration: TwoStepVerificationAccessConfiguration(configuration: configuration, password: nil)))))