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.";
"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, 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 {
switch currentType {
case .otherSession:
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)
}

View File

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

View File

@ -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,8 +1314,7 @@ 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 {
@ -1332,19 +1331,19 @@ public final class CalendarMessageScreen: ViewController {
}
}
let toolbarText: String
if selectedCount == 0 {
toolbarText = self.presentationData.strings.DialogList_ClearHistoryConfirmation
} else if selectedCount == 1 {
//TODO:localize
toolbarText = "Clear History For This Day"
toolbarText = self.presentationData.strings.MessageCalendar_ClearHistoryForThisDay
} else {
//TODO:localize
toolbarText = "Clear History For These Days"
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
}

View File

@ -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

View File

@ -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)
}

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -105,11 +105,11 @@ public func sendAuthorizationCode(accountManager: AccountManager<TelegramAccount
}
|> `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<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
if let state = transaction.getState() as? UnauthorizedAccountState {
switch state.contents {
@ -302,11 +302,14 @@ public func authorizeWithCode(accountManager: AccountManager<TelegramAccountMana
return .single(.loggedIn)
case let .authorization(authorization):
switch authorization {
case let .authorization(_, _, _, user):
case let .authorization(_, otherwiseReloginDays, _, user):
let user = TelegramUser(user: user)
let state = AuthorizedAccountState(isTestingEnvironment: account.testingEnvironment, masterDatacenterId: account.masterDatacenterId, peerId: user.id, state: nil)
initializedAppSettingsAfterLogin(transaction: transaction, appVersion: account.networkArguments.appVersion, syncContacts: syncContacts)
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
switchToAuthorizedAccount(transaction: transaction, account: account)
return .loggedIn
@ -542,7 +545,7 @@ public enum SignUpError {
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
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<TelegramAccountManager
}
|> mapToSignal { result -> Signal<Void, SignUpError> 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,6 +573,9 @@ public func signUpWithName(accountManager: AccountManager<TelegramAccountManager
}
initializedAppSettingsAfterLogin(transaction: transaction, appVersion: account.networkArguments.appVersion, syncContacts: syncContacts)
transaction.setState(state)
if let otherwiseReloginDays = otherwiseReloginDays, let value = forcedPasswordSetupNotice(otherwiseReloginDays) {
transaction.setNoticeEntry(key: value.0, value: value.1)
}
}
|> castError(SignUpError.self)

View File

@ -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<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> {
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)
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)
}

View File

@ -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 {

View File

@ -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

View File

@ -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)))))