Various improvements

This commit is contained in:
Ali 2021-11-27 00:04:30 +04:00
parent d8c16d872d
commit 5004405e0b
16 changed files with 262 additions and 107 deletions

View File

@ -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."; "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.CheckOtherSessionMessages" = "Check your Telegram messages";
"Login.SendCodeViaSms" = "Send the code as an SMS"; "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.CancelPhoneVerification" = "Do you want to stop the phone number verification process?";
"Login.CancelPhoneVerificationStop" = "Stop"; "Login.CancelPhoneVerificationStop" = "Stop";
"Login.CancelPhoneVerificationContinue" = "Continue"; "Login.CancelPhoneVerificationContinue" = "Continue";
@ -7101,3 +7102,24 @@ Sorry for the inconvenience.";
"AuthSessions.TerminateOtherSessionsText" = "Are you sure you want to terminate all other sessions?"; "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?"; "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, Im sure";
"Login.CodePhonePatternInfoText" = "Please enter the last digits\nof the missed call number.";
"Login.EnterMissingDigits" = "Enter the missing digits";

View File

@ -45,7 +45,14 @@ public func authorizationNextOptionText(currentType: SentAuthorizationCodeType,
} else { } else {
switch currentType { switch currentType {
case .otherSession: 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: default:
return (NSAttributedString(string: strings.Login_HaveNotReceivedCodeInternal, font: Font.regular(16.0), textColor: accentColor, paragraphAlignment: .center), true) return (NSAttributedString(string: strings.Login_HaveNotReceivedCodeInternal, font: Font.regular(16.0), textColor: accentColor, paragraphAlignment: .center), true)
} }

View File

@ -21,6 +21,7 @@ swift_library(
"//submodules/PhotoResources:PhotoResources", "//submodules/PhotoResources:PhotoResources",
"//submodules/DirectMediaImageCache:DirectMediaImageCache", "//submodules/DirectMediaImageCache:DirectMediaImageCache",
"//submodules/TelegramStringFormatting:TelegramStringFormatting", "//submodules/TelegramStringFormatting:TelegramStringFormatting",
"//submodules/TooltipUI:TooltipUI",
], ],
visibility = [ visibility = [
"//visibility:public", "//visibility:public",

View File

@ -11,6 +11,7 @@ import ComponentFlow
import PhotoResources import PhotoResources
import DirectMediaImageCache import DirectMediaImageCache
import TelegramStringFormatting import TelegramStringFormatting
import TooltipUI
private final class NullActionClass: NSObject, CAAction { private final class NullActionClass: NSObject, CAAction {
@objc func run(forKey event: String, object anObject: Any, arguments dict: [AnyHashable : Any]?) { @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 dayEnvironment = context.environment[DayEnvironment.self].value
let dayItemSize = updatedDays[0].size let dayItemSize = updatedDays[0].size
let deltaWidth = floor((weekdayWidth - dayItemSize.width) / 2.0) let selectionRadius: CGFloat = min(dayItemSize.width, dayItemSize.height)
let deltaHeight = floor((weekdaySize - dayItemSize.width) / 2.0)
let deltaWidth = floor((weekdayWidth - selectionRadius) / 2.0)
let deltaHeight = floor((weekdaySize - selectionRadius) / 2.0)
let minX = sideInset + CGFloat(selection.range.lowerBound) * weekdayWidth + deltaWidth let minX = sideInset + CGFloat(selection.range.lowerBound) * weekdayWidth + deltaWidth
let maxX = sideInset + CGFloat(selection.range.upperBound + 1) * weekdayWidth - deltaWidth let maxX = sideInset + CGFloat(selection.range.upperBound + 1) * weekdayWidth - deltaWidth
let minY = baseDayY + CGFloat(lineIndex) * (weekdaySize + weekdaySpacing) + deltaHeight let minY = baseDayY + CGFloat(lineIndex) * (weekdaySize + weekdaySpacing) + deltaHeight
let maxY = minY + dayItemSize.width let maxY = minY + selectionRadius
let leftRadius: CGFloat = dayItemSize.width
let rightRadius: CGFloat = dayItemSize.width
let monthSelectionColor = context.component.theme.list.itemCheckColors.fillColor.withMultipliedAlpha(0.1) 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 selectionRect = CGRect(origin: CGPoint(x: minX, y: minY), size: CGSize(width: maxX - minX, height: maxY - minY))
let selection = selections[lineIndex].update( 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, availableSize: selectionRect.size,
transition: .immediate transition: .immediate
) )
@ -923,7 +923,7 @@ private final class MonthComponent: CombinedComponent {
} }
let delay = Double(min(delayIndex, 6)) * 0.1 let delay = Double(min(delayIndex, 6)) * 0.1
view.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.05, delay: delay) 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 .disappear(Transition.Disappear { view, transition, completion in
if case .none = transition.animation { if case .none = transition.animation {
@ -1314,37 +1314,36 @@ public final class CalendarMessageScreen: ViewController {
if let selectionState = self.selectionState { if let selectionState = self.selectionState {
let selectionToolbarNode: ToolbarNode let selectionToolbarNode: ToolbarNode
if let currrent = self.selectionToolbarNode { let toolbarText: String
selectionToolbarNode = currrent
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 for day in 0 ..< self.months[i].numberOfDays {
if let dayRange = selectionState.dayRange { let dayTimestamp = firstDayTimestamp + 24 * 60 * 60 * Int32(day)
for i in 0 ..< self.months.count {
let firstDayTimestamp = Int32(self.months[i].firstDay.timeIntervalSince1970)
for day in 0 ..< self.months[i].numberOfDays { if dayRange.contains(dayTimestamp) {
let dayTimestamp = firstDayTimestamp + 24 * 60 * 60 * Int32(day) selectedCount += 1
if dayRange.contains(dayTimestamp) {
selectedCount += 1
}
} }
} }
} }
}
let toolbarText: String
if selectedCount == 0 { if selectedCount == 0 {
toolbarText = self.presentationData.strings.DialogList_ClearHistoryConfirmation toolbarText = self.presentationData.strings.DialogList_ClearHistoryConfirmation
} else if selectedCount == 1 { } else if selectedCount == 1 {
//TODO:localize toolbarText = self.presentationData.strings.MessageCalendar_ClearHistoryForThisDay
toolbarText = "Clear History For This Day" } else {
} else { toolbarText = self.presentationData.strings.MessageCalendar_ClearHistoryForTheseDays
//TODO:localize }
toolbarText = "Clear History For These Days"
} if let currrent = self.selectionToolbarNode {
selectionToolbarNode = currrent
transition.updateFrame(node: selectionToolbarNode, frame: tabBarFrame) 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 { } else {
selectionToolbarNode = ToolbarNode( selectionToolbarNode = ToolbarNode(
theme: TabBarControllerTheme( theme: TabBarControllerTheme(
@ -1359,7 +1358,7 @@ public final class CalendarMessageScreen: ViewController {
} }
) )
selectionToolbarNode.frame = tabBarFrame 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.addSubnode(selectionToolbarNode)
self.selectionToolbarNode = selectionToolbarNode self.selectionToolbarNode = selectionToolbarNode
transition.animatePositionAdditive(node: selectionToolbarNode, offset: CGPoint(x: 0.0, y: tabBarFrame.height)) transition.animatePositionAdditive(node: selectionToolbarNode, offset: CGPoint(x: 0.0, y: tabBarFrame.height))
@ -1425,6 +1424,16 @@ public final class CalendarMessageScreen: ViewController {
} }
private func selectionToolbarActionSelected() { 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 { guard let selectionState = self.selectionState, let dayRange = selectionState.dayRange else {
return return
} }

View File

@ -24,6 +24,7 @@ import TelegramIntents
import TooltipUI import TooltipUI
import TelegramCallsUI import TelegramCallsUI
import StickerResources import StickerResources
import PasswordSetupUI
private func fixListNodeScrolling(_ listNode: ListView, searchNode: NavigationBarSearchContentNode) -> Bool { private func fixListNodeScrolling(_ listNode: ListView, searchNode: NavigationBarSearchContentNode) -> Bool {
if listNode.scroller.isDragging { if listNode.scroller.isDragging {
@ -1264,6 +1265,53 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
}) })
], actionLayout: .vertical, parseMarkdown: true), in: .window(.root)) ], 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 self.chatListDisplayNode.containerNode.addedVisibleChatsWithPeerIds = { [weak self] peerIds in

View File

@ -101,9 +101,9 @@ public final class ConstantDisplayLinkAnimator {
self.displayLink = CADisplayLink(target: DisplayLinkTarget({ [weak self] in self.displayLink = CADisplayLink(target: DisplayLinkTarget({ [weak self] in
self?.tick() self?.tick()
}), selector: #selector(DisplayLinkTarget.event)) }), 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?.preferredFrameRateRange = CAFrameRateRange(minimum: 60.0, maximum: 120.0, preferred: 120.0)
} }*/
self.displayLink.isPaused = true self.displayLink.isPaused = true
self.displayLink.add(to: RunLoop.main, forMode: .common) self.displayLink.add(to: RunLoop.main, forMode: .common)
} }

View File

@ -35,14 +35,14 @@ public enum TwoFactorDataInputMode {
case authorized case authorized
} }
case password case password(doneText: String)
case passwordRecoveryEmail(emailPattern: String, mode: PasswordRecoveryEmailMode) case passwordRecoveryEmail(emailPattern: String, mode: PasswordRecoveryEmailMode, doneText: String)
case passwordRecovery(Recovery) case passwordRecovery(recovery: Recovery, doneText: String)
case emailAddress(password: String, hint: String) case emailAddress(password: String, hint: String, doneText: String)
case updateEmailAddress(password: String) case updateEmailAddress(password: String, doneText: String)
case emailConfirmation(passwordAndHint: (String, String)?, emailPattern: String, codeLength: Int?) case emailConfirmation(passwordAndHint: (String, String)?, emailPattern: String, codeLength: Int?, doneText: String)
case passwordHint(recovery: Recovery?, password: String) case passwordHint(recovery: Recovery?, password: String, doneText: String)
case rememberPassword case rememberPassword(doneText: String)
} }
public final class TwoFactorDataInputScreen: ViewController { public final class TwoFactorDataInputScreen: ViewController {
@ -110,7 +110,7 @@ public final class TwoFactorDataInputScreen: ViewController {
return return
} }
switch strongSelf.mode { switch strongSelf.mode {
case .password: case let .password(doneText):
let values = (strongSelf.displayNode as! TwoFactorDataInputScreenNode).inputText let values = (strongSelf.displayNode as! TwoFactorDataInputScreenNode).inputText
if values.count != 2 { if values.count != 2 {
return return
@ -136,9 +136,9 @@ public final class TwoFactorDataInputScreen: ViewController {
} }
return true 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) 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 { guard let text = (strongSelf.displayNode as! TwoFactorDataInputScreenNode).inputText.first, !text.isEmpty else {
return return
} }
@ -180,14 +180,14 @@ public final class TwoFactorDataInputScreen: ViewController {
mappedMode = .notAuthorized(syncContacts: syncContacts) 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 { guard let navigationController = strongSelf.navigationController as? NavigationController else {
return return
} }
navigationController.replaceController(strongSelf, with: setupController, animated: true) navigationController.replaceController(strongSelf, with: setupController, animated: true)
})) }))
case let .passwordRecovery(recovery): case let .passwordRecovery(recovery, doneText):
let values = (strongSelf.displayNode as! TwoFactorDataInputScreenNode).inputText let values = (strongSelf.displayNode as! TwoFactorDataInputScreenNode).inputText
if values.count != 2 { if values.count != 2 {
return return
@ -204,8 +204,8 @@ public final class TwoFactorDataInputScreen: ViewController {
guard let navigationController = strongSelf.navigationController as? NavigationController else { guard let navigationController = strongSelf.navigationController as? NavigationController else {
return 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) 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): case let .emailAddress(password, hint, doneText):
guard let text = (strongSelf.displayNode as! TwoFactorDataInputScreenNode).inputText.first, !text.isEmpty else { guard let text = (strongSelf.displayNode as! TwoFactorDataInputScreenNode).inputText.first, !text.isEmpty else {
return return
} }
@ -237,7 +237,7 @@ public final class TwoFactorDataInputScreen: ViewController {
} }
return true 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) navigationController.setViewControllers(controllers, animated: true)
} else { } else {
guard let navigationController = strongSelf.navigationController as? NavigationController else { guard let navigationController = strongSelf.navigationController as? NavigationController else {
@ -252,7 +252,7 @@ public final class TwoFactorDataInputScreen: ViewController {
} }
return true 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) 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)) 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 { guard let text = (strongSelf.displayNode as! TwoFactorDataInputScreenNode).inputText.first, !text.isEmpty else {
return return
} }
@ -307,7 +307,7 @@ public final class TwoFactorDataInputScreen: ViewController {
} }
return true 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) navigationController.setViewControllers(controllers, animated: true)
} else { } else {
guard let navigationController = strongSelf.navigationController as? NavigationController else { guard let navigationController = strongSelf.navigationController as? NavigationController else {
@ -322,7 +322,7 @@ public final class TwoFactorDataInputScreen: ViewController {
} }
return true 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) navigationController.setViewControllers(controllers, animated: true)
} }
} }
@ -346,7 +346,7 @@ public final class TwoFactorDataInputScreen: ViewController {
case .unauthorized: case .unauthorized:
break break
} }
case .emailConfirmation: case let .emailConfirmation(_, _, _, doneText):
guard let text = (strongSelf.displayNode as! TwoFactorDataInputScreenNode).inputText.first, !text.isEmpty else { guard let text = (strongSelf.displayNode as! TwoFactorDataInputScreenNode).inputText.first, !text.isEmpty else {
return return
} }
@ -397,13 +397,13 @@ public final class TwoFactorDataInputScreen: ViewController {
} }
return true 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) navigationController.setViewControllers(controllers, animated: true)
}) })
case .unauthorized: case .unauthorized:
break break
} }
case let .passwordHint(recovery, password): case let .passwordHint(recovery, password, doneText):
guard let value = (strongSelf.displayNode as! TwoFactorDataInputScreenNode).inputText.first, !value.isEmpty else { guard let value = (strongSelf.displayNode as! TwoFactorDataInputScreenNode).inputText.first, !value.isEmpty else {
return return
} }
@ -411,7 +411,7 @@ public final class TwoFactorDataInputScreen: ViewController {
if let recovery = recovery { if let recovery = recovery {
strongSelf.performRecovery(recovery: recovery, password: password, hint: value) strongSelf.performRecovery(recovery: recovery, password: password, hint: value)
} else { } 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: case .rememberPassword:
guard case let .authorized(engine) = strongSelf.engine else { guard case let .authorized(engine) = strongSelf.engine else {
@ -476,7 +476,7 @@ public final class TwoFactorDataInputScreen: ViewController {
return return
} }
switch strongSelf.mode { 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: [ 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: { TextAlertAction(type: .destructiveAction, title: strongSelf.presentationData.strings.TwoFactorSetup_Email_SkipConfirmationSkip, action: {
guard let strongSelf = self else { guard let strongSelf = self else {
@ -509,7 +509,7 @@ public final class TwoFactorDataInputScreen: ViewController {
} }
return true 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) navigationController.setViewControllers(controllers, animated: true)
} }
}, error: { [weak statusController] error in }, error: { [weak statusController] error in
@ -532,13 +532,13 @@ public final class TwoFactorDataInputScreen: ViewController {
}), }),
TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_Cancel, action: {}) TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_Cancel, action: {})
]), in: .window(.root)) ]), in: .window(.root))
case let .passwordHint(recovery, password): case let .passwordHint(recovery, password, doneText):
if let recovery = recovery { if let recovery = recovery {
strongSelf.performRecovery(recovery: recovery, password: password, hint: "") strongSelf.performRecovery(recovery: recovery, password: password, hint: "")
} else { } 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: [ 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: { TextAlertAction(type: .destructiveAction, title: strongSelf.presentationData.strings.TwoFactorSetup_PasswordRecovery_SkipAlertAction, action: {
guard let strongSelf = self else { guard let strongSelf = self else {
@ -548,7 +548,7 @@ public final class TwoFactorDataInputScreen: ViewController {
}), }),
TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_Cancel, action: {}) TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_Cancel, action: {})
]), in: .window(.root)) ]), in: .window(.root))
case .rememberPassword: case let .rememberPassword(doneText):
guard case let .authorized(engine) = strongSelf.engine else { guard case let .authorized(engine) = strongSelf.engine else {
return return
} }
@ -575,7 +575,7 @@ public final class TwoFactorDataInputScreen: ViewController {
disposable.set((engine.auth.requestTwoStepVerificationPasswordRecoveryCode() disposable.set((engine.auth.requestTwoStepVerificationPasswordRecoveryCode()
|> deliverOnMainQueue).start(next: { emailPattern in |> deliverOnMainQueue).start(next: { emailPattern in
var stateUpdated: ((SetupTwoStepVerificationStateUpdate) -> Void)? 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?(state)
}) })
stateUpdated = { [weak controller] state in stateUpdated = { [weak controller] state in
@ -706,7 +706,7 @@ public final class TwoFactorDataInputScreen: ViewController {
return return
} }
switch strongSelf.mode { switch strongSelf.mode {
case let .emailConfirmation(passwordAndHint, _, _): case let .emailConfirmation(passwordAndHint, _, _, doneText):
if let (password, hint) = passwordAndHint { if let (password, hint) = passwordAndHint {
guard let navigationController = strongSelf.navigationController as? NavigationController else { guard let navigationController = strongSelf.navigationController as? NavigationController else {
return return
@ -720,7 +720,7 @@ public final class TwoFactorDataInputScreen: ViewController {
} }
return true 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) navigationController.setViewControllers(controllers, animated: true)
} else { } else {
} }
@ -1371,7 +1371,7 @@ private final class TwoFactorDataInputScreenNode: ViewControllerTracingNode, UIS
toggleTextHidden?(node) toggleTextHidden?(node)
}), }),
] ]
case let .passwordRecoveryEmail(emailPattern, _): case let .passwordRecoveryEmail(emailPattern, _, _):
title = presentationData.strings.TwoFactorSetup_EmailVerification_Title title = presentationData.strings.TwoFactorSetup_EmailVerification_Title
let formattedString = presentationData.strings.TwoFactorSetup_EmailVerification_Text(emailPattern) let formattedString = presentationData.strings.TwoFactorSetup_EmailVerification_Text(emailPattern)
@ -1398,7 +1398,7 @@ private final class TwoFactorDataInputScreenNode: ViewControllerTracingNode, UIS
toggleTextHidden?(node) toggleTextHidden?(node)
}), }),
] ]
case let .emailConfirmation(_, emailPattern, _): case let .emailConfirmation(_, emailPattern, _, _):
title = presentationData.strings.TwoFactorSetup_EmailVerification_Title title = presentationData.strings.TwoFactorSetup_EmailVerification_Title
let formattedString = presentationData.strings.TwoFactorSetup_EmailVerification_Text(emailPattern) let formattedString = presentationData.strings.TwoFactorSetup_EmailVerification_Text(emailPattern)
@ -1654,7 +1654,7 @@ private final class TwoFactorDataInputScreenNode: ViewControllerTracingNode, UIS
strongSelf.buttonNode.isHidden = !hasText strongSelf.buttonNode.isHidden = !hasText
strongSelf.skipActionTitleNode.isHidden = hasText strongSelf.skipActionTitleNode.isHidden = hasText
strongSelf.skipActionButtonNode.isHidden = hasText strongSelf.skipActionButtonNode.isHidden = hasText
case let .emailConfirmation(_, _, codeLength): case let .emailConfirmation(_, _, codeLength, _):
let text = strongSelf.inputNodes[0].text let text = strongSelf.inputNodes[0].text
let hasText = !text.isEmpty let hasText = !text.isEmpty
strongSelf.buttonNode.isHidden = !hasText strongSelf.buttonNode.isHidden = !hasText

View File

@ -13,8 +13,27 @@ import PresentationDataUtils
import TelegramCore import TelegramCore
public enum TwoFactorAuthSplashMode { public enum TwoFactorAuthSplashMode {
case intro public struct Intro {
case done 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 recoveryDone(recoveredAccountData: RecoveredAccountData?, syncContacts: Bool, isPasswordSet: Bool)
case remember case remember
} }
@ -25,6 +44,8 @@ public final class TwoFactorAuthSplashScreen: ViewController {
private var presentationData: PresentationData private var presentationData: PresentationData
private var mode: TwoFactorAuthSplashMode private var mode: TwoFactorAuthSplashMode
public var dismissConfirmation: ((@escaping () -> Void) -> Bool)?
public init(sharedContext: SharedAccountContext, engine: SomeTelegramEngine, mode: TwoFactorAuthSplashMode, presentation: ViewControllerNavigationPresentation = .modalInLargeLayout) { public init(sharedContext: SharedAccountContext, engine: SomeTelegramEngine, mode: TwoFactorAuthSplashMode, presentation: ViewControllerNavigationPresentation = .modalInLargeLayout) {
self.sharedContext = sharedContext self.sharedContext = sharedContext
self.engine = engine self.engine = engine
@ -55,6 +76,14 @@ public final class TwoFactorAuthSplashScreen: ViewController {
} else { } else {
self.navigationItem.leftBarButtonItem = UIBarButtonItem(customDisplayNode: ASDisplayNode()) 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) { required init(coder aDecoder: NSCoder) {
@ -70,8 +99,8 @@ public final class TwoFactorAuthSplashScreen: ViewController {
return return
} }
switch strongSelf.mode { switch strongSelf.mode {
case .intro: case let .intro(intro):
strongSelf.push(TwoFactorDataInputScreen(sharedContext: strongSelf.sharedContext, engine: strongSelf.engine, mode: .password, stateUpdated: { _ in strongSelf.push(TwoFactorDataInputScreen(sharedContext: strongSelf.sharedContext, engine: strongSelf.engine, mode: .password(doneText: intro.doneText), stateUpdated: { _ in
}, presentation: strongSelf.navigationPresentation)) }, presentation: strongSelf.navigationPresentation))
case .done, .remember: case .done, .remember:
guard let navigationController = strongSelf.navigationController as? NavigationController else { guard let navigationController = strongSelf.navigationController as? NavigationController else {
@ -136,18 +165,18 @@ private final class TwoFactorAuthSplashScreenNode: ViewControllerTracingNode {
let textColor = self.presentationData.theme.list.itemPrimaryTextColor let textColor = self.presentationData.theme.list.itemPrimaryTextColor
switch mode { switch mode {
case .intro: case let .intro(intro):
title = self.presentationData.strings.TwoFactorSetup_Intro_Title title = intro.title
texts = [NSAttributedString(string: self.presentationData.strings.TwoFactorSetup_Intro_Text, font: textFont, textColor: textColor)] texts = [NSAttributedString(string: intro.text, font: textFont, textColor: textColor)]
buttonText = self.presentationData.strings.TwoFactorSetup_Intro_Action buttonText = intro.actionText
self.animationNode.setup(source: AnimatedStickerNodeLocalFileSource(name: "TwoFactorSetupIntro"), width: 248, height: 248, playbackMode: .once, mode: .direct(cachePathPrefix: nil)) 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.animationSize = CGSize(width: 124.0, height: 124.0)
self.animationNode.visibility = true self.animationNode.visibility = true
case .done: case let .done(doneText):
title = self.presentationData.strings.TwoFactorSetup_Done_Title title = self.presentationData.strings.TwoFactorSetup_Done_Title
texts = [NSAttributedString(string: self.presentationData.strings.TwoFactorSetup_Done_Text, font: textFont, textColor: textColor)] 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.animationNode.setup(source: AnimatedStickerNodeLocalFileSource(name: "TwoFactorSetupDone"), width: 248, height: 248, mode: .direct(cachePathPrefix: nil))
self.animationSize = CGSize(width: 124.0, height: 124.0) self.animationSize = CGSize(width: 124.0, height: 124.0)

View File

@ -732,7 +732,13 @@ public func privacyAndSecurityController(context: AccountContext, initialSetting
break break
case let .notSet(pendingEmail): case let .notSet(pendingEmail):
if pendingEmail == nil { 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) pushControllerImpl?(controller, true)
return return

View File

@ -509,7 +509,7 @@ public func twoStepVerificationUnlockSettingsController(context: AccountContext,
} }
var stateUpdated: ((SetupTwoStepVerificationStateUpdate) -> Void)? 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?(state)
}) })
stateUpdated = { [weak controller] state in stateUpdated = { [weak controller] state in

View File

@ -105,11 +105,11 @@ public func sendAuthorizationCode(accountManager: AccountManager<TelegramAccount
} }
|> `catch` { error -> Signal<(SendCodeResult, UnauthorizedAccount), MTRpcError> in |> `catch` { error -> Signal<(SendCodeResult, UnauthorizedAccount), MTRpcError> in
if error.errorDescription == "SESSION_PASSWORD_NEEDED" { 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 |> mapToSignal { result -> Signal<(SendCodeResult, UnauthorizedAccount), MTRpcError> in
switch result { switch result {
case let .password(_, _, _, _, hint, _, _, _, _, _): case let .password(_, _, _, _, hint, _, _, _, _, _):
return .single((.password(hint: hint), account)) return .single((.password(hint: hint), updatedAccount))
} }
} }
} else { } else {
@ -252,7 +252,7 @@ public enum AuthorizeWithCodeResult {
case loggedIn case loggedIn
} }
public func authorizeWithCode(accountManager: AccountManager<TelegramAccountManagerTypes>, account: UnauthorizedAccount, code: String, termsOfService: UnauthorizedAccountTermsOfService?) -> Signal<AuthorizeWithCodeResult, AuthorizationCodeVerificationError> { public func authorizeWithCode(accountManager: AccountManager<TelegramAccountManagerTypes>, account: UnauthorizedAccount, code: String, termsOfService: UnauthorizedAccountTermsOfService?, forcedPasswordSetupNotice: @escaping (Int32) -> (NoticeEntryKey, CodableEntry)?) -> Signal<AuthorizeWithCodeResult, AuthorizationCodeVerificationError> {
return account.postbox.transaction { transaction -> Signal<AuthorizeWithCodeResult, AuthorizationCodeVerificationError> in return account.postbox.transaction { transaction -> Signal<AuthorizeWithCodeResult, AuthorizationCodeVerificationError> in
if let state = transaction.getState() as? UnauthorizedAccountState { if let state = transaction.getState() as? UnauthorizedAccountState {
switch state.contents { switch state.contents {
@ -302,11 +302,14 @@ public func authorizeWithCode(accountManager: AccountManager<TelegramAccountMana
return .single(.loggedIn) return .single(.loggedIn)
case let .authorization(authorization): case let .authorization(authorization):
switch authorization { switch authorization {
case let .authorization(_, _, _, user): case let .authorization(_, otherwiseReloginDays, _, user):
let user = TelegramUser(user: user) let user = TelegramUser(user: user)
let state = AuthorizedAccountState(isTestingEnvironment: account.testingEnvironment, masterDatacenterId: account.masterDatacenterId, peerId: user.id, state: nil) let state = AuthorizedAccountState(isTestingEnvironment: account.testingEnvironment, masterDatacenterId: account.masterDatacenterId, peerId: user.id, state: nil)
initializedAppSettingsAfterLogin(transaction: transaction, appVersion: account.networkArguments.appVersion, syncContacts: syncContacts) initializedAppSettingsAfterLogin(transaction: transaction, appVersion: account.networkArguments.appVersion, syncContacts: syncContacts)
transaction.setState(state) transaction.setState(state)
if let otherwiseReloginDays = otherwiseReloginDays, let value = forcedPasswordSetupNotice(otherwiseReloginDays) {
transaction.setNoticeEntry(key: value.0, value: value.1)
}
return accountManager.transaction { transaction -> AuthorizeWithCodeResult in return accountManager.transaction { transaction -> AuthorizeWithCodeResult in
switchToAuthorizedAccount(transaction: transaction, account: account) switchToAuthorizedAccount(transaction: transaction, account: account)
return .loggedIn return .loggedIn
@ -542,7 +545,7 @@ public enum SignUpError {
case invalidLastName case invalidLastName
} }
public func signUpWithName(accountManager: AccountManager<TelegramAccountManagerTypes>, account: UnauthorizedAccount, firstName: String, lastName: String, avatarData: Data?, avatarVideo: Signal<UploadedPeerPhotoData?, NoError>?, videoStartTimestamp: Double?) -> Signal<Void, SignUpError> { public func signUpWithName(accountManager: AccountManager<TelegramAccountManagerTypes>, account: UnauthorizedAccount, firstName: String, lastName: String, avatarData: Data?, avatarVideo: Signal<UploadedPeerPhotoData?, NoError>?, videoStartTimestamp: Double?, forcedPasswordSetupNotice: @escaping (Int32) -> (NoticeEntryKey, CodableEntry)?) -> Signal<Void, SignUpError> {
return account.postbox.transaction { transaction -> Signal<Void, SignUpError> in return account.postbox.transaction { transaction -> Signal<Void, SignUpError> in
if let state = transaction.getState() as? UnauthorizedAccountState, case let .signUp(number, codeHash, _, _, _, syncContacts) = state.contents { 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)) 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<TelegramAccountManager
} }
|> mapToSignal { result -> Signal<Void, SignUpError> in |> mapToSignal { result -> Signal<Void, SignUpError> in
switch result { switch result {
case let .authorization(_, _, _, user): case let .authorization(_, otherwiseReloginDays, _, user):
let user = TelegramUser(user: user) let user = TelegramUser(user: user)
let appliedState = account.postbox.transaction { transaction -> Void in let appliedState = account.postbox.transaction { transaction -> Void in
let state = AuthorizedAccountState(isTestingEnvironment: account.testingEnvironment, masterDatacenterId: account.masterDatacenterId, peerId: user.id, state: nil) let state = AuthorizedAccountState(isTestingEnvironment: account.testingEnvironment, masterDatacenterId: account.masterDatacenterId, peerId: user.id, state: nil)
@ -570,8 +573,11 @@ public func signUpWithName(accountManager: AccountManager<TelegramAccountManager
} }
initializedAppSettingsAfterLogin(transaction: transaction, appVersion: account.networkArguments.appVersion, syncContacts: syncContacts) initializedAppSettingsAfterLogin(transaction: transaction, appVersion: account.networkArguments.appVersion, syncContacts: syncContacts)
transaction.setState(state) transaction.setState(state)
if let otherwiseReloginDays = otherwiseReloginDays, let value = forcedPasswordSetupNotice(otherwiseReloginDays) {
transaction.setNoticeEntry(key: value.0, value: value.1)
} }
|> castError(SignUpError.self) }
|> castError(SignUpError.self)
let switchedAccounts = accountManager.transaction { transaction -> Void in let switchedAccounts = accountManager.transaction { transaction -> Void in
switchToAuthorizedAccount(transaction: transaction, account: account) switchToAuthorizedAccount(transaction: transaction, account: account)

View File

@ -162,6 +162,7 @@ private enum ApplicationSpecificGlobalNotice: Int32 {
case interactiveEmojiSyncTip = 28 case interactiveEmojiSyncTip = 28
case sharedMediaScrollingTooltip = 29 case sharedMediaScrollingTooltip = 29
case sharedMediaFastScrollingTooltip = 30 case sharedMediaFastScrollingTooltip = 30
case forcedPasswordSetup = 31
var key: ValueBoxKey { var key: ValueBoxKey {
let v = ValueBoxKey(length: 4) let v = ValueBoxKey(length: 4)
@ -211,6 +212,10 @@ private struct ApplicationSpecificNoticeKeys {
return NoticeEntryKey(namespace: noticeNamespace(namespace: peerReportNamespace), key: noticeKey(peerId: peerId, key: 0)) 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 { static func secretChatInlineBotUsage() -> NoticeEntryKey {
return NoticeEntryKey(namespace: noticeNamespace(namespace: globalNamespace), key: ApplicationSpecificGlobalNotice.secretChatInlineBotUsage.key) 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<Never, NoError> {
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<TelegramAccountManagerTypes>) -> Signal<Void, NoError> { public static func reset(accountManager: AccountManager<TelegramAccountManagerTypes>) -> Signal<Void, NoError> {
return accountManager.transaction { transaction -> Void in return accountManager.transaction { transaction -> Void in
} }

View File

@ -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) self.currentOptionNode.attributedText = authorizationCurrentOptionText(codeType, strings: self.strings, primaryColor: self.theme.list.itemPrimaryTextColor, accentColor: self.theme.list.itemAccentColor)
if case .missedCall = codeType { if case .missedCall = codeType {
//TODO:localize self.currentOptionInfoNode.attributedText = NSAttributedString(string: self.strings.Login_CodePhonePatternInfoText, font: Font.regular(16.0), textColor: self.theme.list.itemPrimaryTextColor, paragraphAlignment: .center)
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)
} else { } else {
self.currentOptionInfoNode.attributedText = NSAttributedString(string: "", font: Font.regular(15.0), textColor: self.theme.list.itemPrimaryTextColor) 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: case .otherSession:
self.titleNode.attributedText = NSAttributedString(string: self.strings.Login_CheckOtherSessionMessages, font: Font.medium(32.0), textColor: self.theme.list.itemPrimaryTextColor) self.titleNode.attributedText = NSAttributedString(string: self.strings.Login_CheckOtherSessionMessages, font: Font.medium(32.0), textColor: self.theme.list.itemPrimaryTextColor)
case .missedCall: case .missedCall:
//TODO:localize self.titleNode.attributedText = NSAttributedString(string: self.strings.Login_EnterMissingDigits, font: Font.medium(32.0), textColor: self.theme.list.itemPrimaryTextColor)
self.titleNode.attributedText = NSAttributedString(string: "Enter the missing digits", font: Font.medium(32.0), textColor: self.theme.list.itemPrimaryTextColor)
default: default:
self.titleNode.attributedText = NSAttributedString(string: self.phoneNumber, font: Font.light(40.0), textColor: self.theme.list.itemPrimaryTextColor) 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 { } else {
fontSize = 18.0 fontSize = 18.0
} }
//TODO:localize self.titleNode.attributedText = NSAttributedString(string: self.strings.Login_EnterMissingDigits, font: Font.semibold(fontSize), textColor: self.theme.list.itemPrimaryTextColor)
self.titleNode.attributedText = NSAttributedString(string: "Enter the missing digits", font: Font.semibold(fontSize), textColor: self.theme.list.itemPrimaryTextColor)
default: default:
self.titleNode.attributedText = NSAttributedString(string: self.phoneNumber, font: Font.light(30.0), textColor: self.theme.list.itemPrimaryTextColor) self.titleNode.attributedText = NSAttributedString(string: self.phoneNumber, font: Font.light(30.0), textColor: self.theme.list.itemPrimaryTextColor)
} }

View File

@ -17,6 +17,7 @@ import PhoneNumberFormat
import LegacyComponents import LegacyComponents
import LegacyMediaPickerUI import LegacyMediaPickerUI
import PasswordSetupUI import PasswordSetupUI
import TelegramNotices
private enum InnerState: Equatable { private enum InnerState: Equatable {
case state(UnauthorizedAccountStateContents) case state(UnauthorizedAccountStateContents)
@ -289,7 +290,12 @@ public final class AuthorizationSequenceController: NavigationController, MFMail
if let strongSelf = self { if let strongSelf = self {
controller?.inProgress = true 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 |> deliverOnMainQueue).start(next: { result in
guard let strongSelf = self else { guard let strongSelf = self else {
return return
@ -553,7 +559,7 @@ public final class AuthorizationSequenceController: NavigationController, MFMail
if let currentController = currentController { if let currentController = currentController {
controller = currentController controller = currentController
} else { } 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) }, presentation: .default)
} }
controller.passwordRecoveryFailed = { [weak self] in controller.passwordRecoveryFailed = { [weak self] in
@ -713,7 +719,12 @@ public final class AuthorizationSequenceController: NavigationController, MFMail
avatarVideo = nil 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 |> deliverOnMainQueue).start(error: { error in
Queue.mainQueue().async { Queue.mainQueue().async {
if let strongSelf = self, let controller = controller { if let strongSelf = self, let controller = controller {

View File

@ -11864,16 +11864,13 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
return return
} }
//TODO:localize let statusText: String
var statusText: String
statusText = "Messages for \(dayCount) \(dayCount == 1 ? "day" : "days") deleted"
switch type { switch type {
case .forEveryone: case .forEveryone:
statusText += " for both sides" statusText = strongSelf.presentationData.strings.Chat_MessageRangeDeleted_ForBothSides(Int32(dayCount))
default: default:
break statusText = strongSelf.presentationData.strings.Chat_MessageRangeDeleted_ForMe(Int32(dayCount))
} }
statusText += "."
strongSelf.chatDisplayNode.historyNode.ignoreMessagesInTimestampRange = range strongSelf.chatDisplayNode.historyNode.ignoreMessagesInTimestampRange = range

View File

@ -5496,7 +5496,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
} }
case .rememberPassword: case .rememberPassword:
let context = self.context 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) }, presentation: .modalInLargeLayout)
controller.twoStepAuthSettingsController = { configuration in controller.twoStepAuthSettingsController = { configuration in
return twoStepVerificationUnlockSettingsController(context: context, mode: .access(intro: false, data: .single(TwoStepVerificationUnlockSettingsControllerData.access(configuration: TwoStepVerificationAccessConfiguration(configuration: configuration, password: nil))))) return twoStepVerificationUnlockSettingsController(context: context, mode: .access(intro: false, data: .single(TwoStepVerificationUnlockSettingsControllerData.access(configuration: TwoStepVerificationAccessConfiguration(configuration: configuration, password: nil)))))