no message

This commit is contained in:
Ilya Laktyushin 2018-09-07 00:35:43 +03:00
parent 1fc691a800
commit 43bbabfcbc
17 changed files with 288 additions and 128 deletions

View File

@ -90,6 +90,46 @@ public enum AvatarNodeColorOverride {
case blue case blue
} }
public final class AvatarEditOverlayNode: ASDisplayNode {
override public init() {
super.init()
self.isOpaque = false
self.displaysAsynchronously = true
}
@objc override public class func draw(_ bounds: CGRect, withParameters parameters: Any?, isCancelled: () -> Bool, isRasterizing: Bool) {
assertNotOnMainThread()
let context = UIGraphicsGetCurrentContext()!
if !isRasterizing {
context.setBlendMode(.copy)
context.setFillColor(UIColor.clear.cgColor)
context.fill(bounds)
}
context.beginPath()
context.addEllipse(in: CGRect(x: 0.0, y: 0.0, width: bounds.size.width, height:
bounds.size.height))
context.clip()
context.setFillColor(UIColor(rgb: 0x000000, alpha: 0.4).cgColor)
context.fill(bounds)
context.translateBy(x: bounds.size.width / 2.0, y: bounds.size.height / 2.0)
context.scaleBy(x: 1.0, y: -1.0)
context.translateBy(x: -bounds.size.width / 2.0, y: -bounds.size.height / 2.0)
context.setBlendMode(.normal)
if let editAvatarIcon = generateTintedImage(image: UIImage(bundleImageName: "Avatar/EditAvatarIcon"), color: .white) {
context.draw(editAvatarIcon.cgImage!, in: CGRect(origin: CGPoint(x: floor((bounds.size.width - editAvatarIcon.size.width) / 2.0), y: floor((bounds.size.height - editAvatarIcon.size.height) / 2.0)), size: editAvatarIcon.size))
}
}
}
public final class AvatarNode: ASDisplayNode { public final class AvatarNode: ASDisplayNode {
var font: UIFont { var font: UIFont {
didSet { didSet {
@ -107,6 +147,7 @@ public final class AvatarNode: ASDisplayNode {
private var parameters: AvatarNodeParameters? private var parameters: AvatarNodeParameters?
private var theme: PresentationTheme? private var theme: PresentationTheme?
let imageNode: ImageNode let imageNode: ImageNode
var editOverlayNode: AvatarEditOverlayNode?
private let imageReadyDisposable = MetaDisposable() private let imageReadyDisposable = MetaDisposable()
private var state: AvatarNodeState = .empty private var state: AvatarNodeState = .empty
@ -143,8 +184,10 @@ public final class AvatarNode: ASDisplayNode {
let updateImage = !value.size.equalTo(super.frame.size) let updateImage = !value.size.equalTo(super.frame.size)
super.frame = value super.frame = value
self.imageNode.frame = CGRect(origin: CGPoint(), size: value.size) self.imageNode.frame = CGRect(origin: CGPoint(), size: value.size)
self.editOverlayNode?.frame = self.imageNode.frame
if updateImage && !self.displaySuspended { if updateImage && !self.displaySuspended {
self.setNeedsDisplay() self.setNeedsDisplay()
self.editOverlayNode?.setNeedsDisplay()
} }
} }
} }
@ -177,11 +220,24 @@ public final class AvatarNode: ASDisplayNode {
self.displaySuspended = true self.displaySuspended = true
self.contents = nil self.contents = nil
let theme = account.telegramApplicationContext.currentPresentationData.with { $0 }.theme
if let signal = peerAvatarImage(account: account, peer: peer, authorOfMessage: authorOfMessage, representation: representation) { if let signal = peerAvatarImage(account: account, peer: peer, authorOfMessage: authorOfMessage, representation: representation) {
self.imageReady.set(self.imageNode.ready) self.imageReady.set(self.imageNode.ready)
self.imageNode.setSignal(signal) self.imageNode.setSignal(signal)
parameters = AvatarNodeParameters(theme: account.telegramApplicationContext.currentPresentationData.with { $0 }.theme, accountPeerId: account.peerId, peerId: peer.id, letters: peer.displayLetters, font: self.font, icon: icon, explicitColorIndex: nil, hasImage: true) if case .editAvatarIcon = icon {
if self.editOverlayNode == nil {
let editOverlayNode = AvatarEditOverlayNode()
editOverlayNode.frame = self.imageNode.frame
self.addSubnode(editOverlayNode)
self.editOverlayNode = editOverlayNode
}
self.editOverlayNode?.isHidden = false
}
parameters = AvatarNodeParameters(theme: theme, accountPeerId: account.peerId, peerId: peer.id, letters: peer.displayLetters, font: self.font, icon: icon, explicitColorIndex: nil, hasImage: true)
} else { } else {
self.imageReady.set(.single(true)) self.imageReady.set(.single(true))
self.displaySuspended = false self.displaySuspended = false
@ -189,7 +245,8 @@ public final class AvatarNode: ASDisplayNode {
self.imageNode.contents = nil self.imageNode.contents = nil
} }
parameters = AvatarNodeParameters(theme: account.telegramApplicationContext.currentPresentationData.with { $0 }.theme, accountPeerId: account.peerId, peerId: peer.id, letters: peer.displayLetters, font: self.font, icon: icon, explicitColorIndex: nil, hasImage: false) self.editOverlayNode?.isHidden = true
parameters = AvatarNodeParameters(theme: theme, accountPeerId: account.peerId, peerId: peer.id, letters: peer.displayLetters, font: self.font, icon: icon, explicitColorIndex: nil, hasImage: false)
} }
if self.parameters == nil || self.parameters != parameters { if self.parameters == nil || self.parameters != parameters {
self.parameters = parameters self.parameters = parameters

View File

@ -114,18 +114,17 @@ final class ChangePhoneNumberController: ViewController {
let text: String let text: String
switch error { switch error {
//TODO
case .limitExceeded: case .limitExceeded:
text = "You have requested authorization code too many times. Please try again later." text = presentationData.strings.Login_CodeFloodError
case .invalidPhoneNumber: case .invalidPhoneNumber:
text = "The phone number you entered is not valid. Please enter the correct number along with your area code." text = presentationData.strings.Login_InvalidPhoneError
case .phoneNumberOccupied: case .phoneNumberOccupied:
text = "The number \(number) is already connected to a Telegram account. Please delete that account before migrating to the new number." text = presentationData.strings.ChangePhone_ErrorOccupied(number).0
case .generic: case .generic:
text = "An error occurred. Please try again later." text = presentationData.strings.Login_UnknownError
} }
strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationTheme: presentationData.theme), title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: "OK", action: {})]), in: .window(.root)) strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationTheme: presentationData.theme), title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root))
} }
})) }))
} else { } else {

View File

@ -180,7 +180,7 @@ public final class ChatController: TelegramController, UIViewControllerPreviewin
self.messageId = messageId self.messageId = messageId
self.botStart = botStart self.botStart = botStart
let locationBroadcastPanelSource: LocationBroadcastPanelSource var locationBroadcastPanelSource: LocationBroadcastPanelSource
switch chatLocation { switch chatLocation {
case let .peer(peerId): case let .peer(peerId):
@ -199,6 +199,8 @@ public final class ChatController: TelegramController, UIViewControllerPreviewin
var enableMediaAccessoryPanel = false var enableMediaAccessoryPanel = false
if case .standard = mode { if case .standard = mode {
enableMediaAccessoryPanel = true enableMediaAccessoryPanel = true
} else {
locationBroadcastPanelSource = .none
} }
let navigationBarPresentationData: NavigationBarPresentationData? let navigationBarPresentationData: NavigationBarPresentationData?
switch mode { switch mode {

View File

@ -49,7 +49,8 @@ func rightNavigationButtonForChatInterfaceState(_ presentationInterfaceState: Ch
} }
} }
if let peer = presentationInterfaceState.renderedPeer?.peer { if case .standard(true) = presentationInterfaceState.mode {
} else if let peer = presentationInterfaceState.renderedPeer?.peer {
if presentationInterfaceState.accountPeerId == peer.id { if presentationInterfaceState.accountPeerId == peer.id {
return ChatNavigationButton(action: .search, buttonItem: UIBarButtonItem(image: PresentationResourcesRootController.navigationCompactSearchIcon(presentationInterfaceState.theme), style: .plain, target: target, action: selector)) return ChatNavigationButton(action: .search, buttonItem: UIBarButtonItem(image: PresentationResourcesRootController.navigationCompactSearchIcon(presentationInterfaceState.theme), style: .plain, target: target, action: selector))
} }

View File

@ -1506,7 +1506,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView {
if let sourceMessageId = forwardInfo.sourceMessageId { if let sourceMessageId = forwardInfo.sourceMessageId {
item.controllerInteraction.navigateToMessage(item.message.id, sourceMessageId) item.controllerInteraction.navigateToMessage(item.message.id, sourceMessageId)
} else { } else {
item.controllerInteraction.openPeer(forwardInfo.source?.id ?? forwardInfo.author.id, .chat(textInputState: nil, messageId: nil), nil) item.controllerInteraction.openPeer(forwardInfo.source?.id ?? forwardInfo.author.id, .info, nil)
} }
return return
} }

View File

@ -14,7 +14,7 @@ final class DateSelectionActionSheetController: ActionSheetController {
return self._ready return self._ready
} }
init(theme: PresentationTheme, strings: PresentationStrings, currentValue: Int32, emptyTitle: String? = nil, applyValue: @escaping (Int32?) -> Void) { init(theme: PresentationTheme, strings: PresentationStrings, currentValue: Int32, minimumDate: Date? = nil, maximumDate: Date? = nil, emptyTitle: String? = nil, applyValue: @escaping (Int32?) -> Void) {
self.theme = theme self.theme = theme
self.strings = strings self.strings = strings
@ -24,7 +24,7 @@ final class DateSelectionActionSheetController: ActionSheetController {
var updatedValue = currentValue var updatedValue = currentValue
var items: [ActionSheetItem] = [] var items: [ActionSheetItem] = []
items.append(DateSelectionActionSheetItem(strings: strings, currentValue: currentValue, valueChanged: { value in items.append(DateSelectionActionSheetItem(strings: strings, currentValue: currentValue, minimumDate: minimumDate, maximumDate: maximumDate, valueChanged: { value in
updatedValue = value updatedValue = value
})) }))
if let emptyTitle = emptyTitle { if let emptyTitle = emptyTitle {
@ -56,16 +56,20 @@ private final class DateSelectionActionSheetItem: ActionSheetItem {
let strings: PresentationStrings let strings: PresentationStrings
let currentValue: Int32 let currentValue: Int32
let minimumDate: Date?
let maximumDate: Date?
let valueChanged: (Int32) -> Void let valueChanged: (Int32) -> Void
init(strings: PresentationStrings, currentValue: Int32, valueChanged: @escaping (Int32) -> Void) { init(strings: PresentationStrings, currentValue: Int32, minimumDate: Date?, maximumDate: Date?, valueChanged: @escaping (Int32) -> Void) {
self.strings = strings self.strings = strings
self.currentValue = roundDateToDays(currentValue) self.currentValue = roundDateToDays(currentValue)
self.minimumDate = minimumDate
self.maximumDate = maximumDate
self.valueChanged = valueChanged self.valueChanged = valueChanged
} }
func node(theme: ActionSheetControllerTheme) -> ActionSheetItemNode { func node(theme: ActionSheetControllerTheme) -> ActionSheetItemNode {
return DateSelectionActionSheetItemNode(theme: theme, strings: self.strings, currentValue: self.currentValue, valueChanged: self.valueChanged) return DateSelectionActionSheetItemNode(theme: theme, strings: self.strings, currentValue: self.currentValue, minimumDate: self.minimumDate, maximumDate: self.maximumDate, valueChanged: self.valueChanged)
} }
func updateNode(_ node: ActionSheetItemNode) { func updateNode(_ node: ActionSheetItemNode) {
@ -79,7 +83,7 @@ private final class DateSelectionActionSheetItemNode: ActionSheetItemNode {
private let valueChanged: (Int32) -> Void private let valueChanged: (Int32) -> Void
private let pickerView: UIDatePicker private let pickerView: UIDatePicker
init(theme: ActionSheetControllerTheme, strings: PresentationStrings, currentValue: Int32, valueChanged: @escaping (Int32) -> Void) { init(theme: ActionSheetControllerTheme, strings: PresentationStrings, currentValue: Int32, minimumDate: Date?, maximumDate: Date?, valueChanged: @escaping (Int32) -> Void) {
self.theme = theme self.theme = theme
self.strings = strings self.strings = strings
self.valueChanged = valueChanged self.valueChanged = valueChanged
@ -88,7 +92,14 @@ private final class DateSelectionActionSheetItemNode: ActionSheetItemNode {
self.pickerView.datePickerMode = .date self.pickerView.datePickerMode = .date
self.pickerView.date = Date(timeIntervalSince1970: Double(roundDateToDays(currentValue))) self.pickerView.date = Date(timeIntervalSince1970: Double(roundDateToDays(currentValue)))
self.pickerView.locale = localeWithStrings(strings) self.pickerView.locale = localeWithStrings(strings)
if let minimumDate = minimumDate {
self.pickerView.minimumDate = minimumDate
}
if let maximumDate = minimumDate {
self.pickerView.maximumDate = maximumDate
} else {
self.pickerView.maximumDate = Date(timeIntervalSince1970: Double(Int32.max - 1)) self.pickerView.maximumDate = Date(timeIntervalSince1970: Double(Int32.max - 1))
}
self.pickerView.setValue(theme.primaryTextColor, forKey: "textColor") self.pickerView.setValue(theme.primaryTextColor, forKey: "textColor")

View File

@ -34,8 +34,8 @@ private enum SettingsEntry: ItemListNodeEntry {
case bioText(PresentationTheme, String, String) case bioText(PresentationTheme, String, String)
case bioInfo(PresentationTheme, String) case bioInfo(PresentationTheme, String)
case username(PresentationTheme, String, String)
case phoneNumber(PresentationTheme, String, String) case phoneNumber(PresentationTheme, String, String)
case username(PresentationTheme, String, String)
case logOut(PresentationTheme, String) case logOut(PresentationTheme, String)
@ -45,7 +45,7 @@ private enum SettingsEntry: ItemListNodeEntry {
return SettingsSection.info.rawValue return SettingsSection.info.rawValue
case .bioText, .bioInfo: case .bioText, .bioInfo:
return SettingsSection.bio.rawValue return SettingsSection.bio.rawValue
case .username, .phoneNumber: case .phoneNumber, .username:
return SettingsSection.personalData.rawValue return SettingsSection.personalData.rawValue
case .logOut: case .logOut:
return SettingsSection.logOut.rawValue return SettingsSection.logOut.rawValue
@ -62,9 +62,9 @@ private enum SettingsEntry: ItemListNodeEntry {
return 2 return 2
case .bioInfo: case .bioInfo:
return 3 return 3
case .username:
return 4
case .phoneNumber: case .phoneNumber:
return 4
case .username:
return 5 return 5
case .logOut: case .logOut:
return 6 return 6
@ -123,14 +123,14 @@ private enum SettingsEntry: ItemListNodeEntry {
} else { } else {
return false return false
} }
case let .username(lhsTheme, lhsText, lhsAddress): case let .phoneNumber(lhsTheme, lhsText, lhsNumber):
if case let .username(rhsTheme, rhsText, rhsAddress) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsAddress == rhsAddress { if case let .phoneNumber(rhsTheme, rhsText, rhsNumber) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsNumber == rhsNumber {
return true return true
} else { } else {
return false return false
} }
case let .phoneNumber(lhsTheme, lhsText, lhsNumber): case let .username(lhsTheme, lhsText, lhsAddress):
if case let .phoneNumber(rhsTheme, rhsText, rhsNumber) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsNumber == rhsNumber { if case let .username(rhsTheme, rhsText, rhsAddress) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsAddress == rhsAddress {
return true return true
} else { } else {
return false return false
@ -166,14 +166,14 @@ private enum SettingsEntry: ItemListNodeEntry {
}) })
case let .bioInfo(theme, text): case let .bioInfo(theme, text):
return ItemListTextItem(theme: theme, text: .plain(text), sectionId: self.section) return ItemListTextItem(theme: theme, text: .plain(text), sectionId: self.section)
case let .username(theme, text, address):
return ItemListDisclosureItem(theme: theme, title: text, label: address, sectionId: ItemListSectionId(self.section), style: .blocks, action: {
arguments.presentController(usernameSetupController(account: arguments.account))
})
case let .phoneNumber(theme, text, number): case let .phoneNumber(theme, text, number):
return ItemListDisclosureItem(theme: theme, title: text, label: number, sectionId: ItemListSectionId(self.section), style: .blocks, action: { return ItemListDisclosureItem(theme: theme, title: text, label: number, sectionId: ItemListSectionId(self.section), style: .blocks, action: {
arguments.pushController(ChangePhoneNumberIntroController(account: arguments.account, phoneNumber: number)) arguments.pushController(ChangePhoneNumberIntroController(account: arguments.account, phoneNumber: number))
}) })
case let .username(theme, text, address):
return ItemListDisclosureItem(theme: theme, title: text, label: address, sectionId: ItemListSectionId(self.section), style: .blocks, action: {
arguments.presentController(usernameSetupController(account: arguments.account))
})
case let .logOut(theme, text): case let .logOut(theme, text):
return ItemListActionItem(theme: theme, title: text, kind: .destructive, alignment: .center, sectionId: ItemListSectionId(self.section), style: .blocks, action: { return ItemListActionItem(theme: theme, title: text, kind: .destructive, alignment: .center, sectionId: ItemListSectionId(self.section), style: .blocks, action: {
arguments.logout() arguments.logout()
@ -248,11 +248,10 @@ private func editSettingsEntries(presentationData: PresentationData, state: Edit
entries.append(.bioText(presentationData.theme, state.editingBioText, presentationData.strings.UserInfo_About_Placeholder)) entries.append(.bioText(presentationData.theme, state.editingBioText, presentationData.strings.UserInfo_About_Placeholder))
entries.append(.bioInfo(presentationData.theme, presentationData.strings.Settings_About_Help)) entries.append(.bioInfo(presentationData.theme, presentationData.strings.Settings_About_Help))
entries.append(.username(presentationData.theme, presentationData.strings.Settings_Username, peer.addressName == nil ? "" : ("@" + peer.addressName!)))
if let phone = peer.phone { if let phone = peer.phone {
entries.append(.phoneNumber(presentationData.theme, presentationData.strings.Settings_PhoneNumber, formatPhoneNumber(phone))) entries.append(.phoneNumber(presentationData.theme, presentationData.strings.Settings_PhoneNumber, formatPhoneNumber(phone)))
} }
entries.append(.username(presentationData.theme, presentationData.strings.Settings_Username, peer.addressName == nil ? "" : ("@" + peer.addressName!)))
entries.append(.logOut(presentationData.theme, presentationData.strings.Settings_Logout)) entries.append(.logOut(presentationData.theme, presentationData.strings.Settings_Logout))
} }
@ -463,7 +462,7 @@ func editSettingsController(account: Account, currentName: ItemListAvatarAndName
} }
let controller = ItemListController(account: account, state: signal, tabBarItem: (account.applicationContext as! TelegramApplicationContext).presentationData |> map { presentationData in let controller = ItemListController(account: account, state: signal, tabBarItem: (account.applicationContext as! TelegramApplicationContext).presentationData |> map { presentationData in
return ItemListControllerTabBarItem(title: presentationData.strings.Settings_Title, image: PresentationResourcesRootController.tabSettingsIcon(presentationData.theme), selectedImage: PresentationResourcesRootController.tabSettingsSelectedIcon(presentationData.theme)) return ItemListControllerTabBarItem(title: presentationData.strings.EditProfile_Title, image: PresentationResourcesRootController.tabSettingsIcon(presentationData.theme), selectedImage: PresentationResourcesRootController.tabSettingsSelectedIcon(presentationData.theme))
}) })
pushControllerImpl = { [weak controller] value in pushControllerImpl = { [weak controller] value in
(controller?.navigationController as? NavigationController)?.pushViewController(value) (controller?.navigationController as? NavigationController)?.pushViewController(value)

View File

@ -5,17 +5,26 @@ import Display
private let textFont = Font.regular(17.0) private let textFont = Font.regular(17.0)
private let errorFont = Font.regular(13.0) private let errorFont = Font.regular(13.0)
enum FormControllerTextInputItemType: Equatable {
case regular(capitalization: UITextAutocapitalizationType, autocorrection: Bool)
case latin
case email
case number
}
final class FormControllerTextInputItem: FormControllerItem { final class FormControllerTextInputItem: FormControllerItem {
let title: String let title: String
let text: String let text: String
let placeholder: String let placeholder: String
let type: FormControllerTextInputItemType
let error: String? let error: String?
let textUpdated: (String) -> Void let textUpdated: (String) -> Void
init(title: String, text: String, placeholder: String, error: String? = nil, textUpdated: @escaping (String) -> Void) { init(title: String, text: String, placeholder: String, type: FormControllerTextInputItemType, error: String? = nil, textUpdated: @escaping (String) -> Void) {
self.title = title self.title = title
self.text = text self.text = text
self.placeholder = placeholder self.placeholder = placeholder
self.type = type
self.error = error self.error = error
self.textUpdated = textUpdated self.textUpdated = textUpdated
} }
@ -81,6 +90,39 @@ final class FormControllerTextInputItemNode: FormBlockItemNode<FormControllerTex
return (FormControllerItemPreLayout(aligningInset: aligningInset), { params in return (FormControllerItemPreLayout(aligningInset: aligningInset), { params in
transition.updateFrame(node: self.titleNode, frame: CGRect(origin: CGPoint(x: leftInset, y: 11.0), size: titleSize)) transition.updateFrame(node: self.titleNode, frame: CGRect(origin: CGPoint(x: leftInset, y: 11.0), size: titleSize))
let capitalizationType: UITextAutocapitalizationType
let autocorrectionType: UITextAutocorrectionType
let keyboardType: UIKeyboardType
switch item.type {
case let .regular(capitalization, autocorrection):
capitalizationType = capitalization
autocorrectionType = autocorrection ? .default : .no
keyboardType = .default
case .latin:
capitalizationType = .words
autocorrectionType = .no
keyboardType = .asciiCapable
case .email:
capitalizationType = .none
autocorrectionType = .no
keyboardType = .emailAddress
case .number:
capitalizationType = .none
autocorrectionType = .no
keyboardType = .numberPad
}
if self.textField.textField.keyboardType != keyboardType {
self.textField.textField.keyboardType = keyboardType
}
if self.textField.textField.autocapitalizationType != capitalizationType {
self.textField.textField.autocapitalizationType = capitalizationType
}
if self.textField.textField.autocorrectionType != autocorrectionType {
self.textField.textField.autocorrectionType = autocorrectionType
}
let attributedPlaceholder = NSAttributedString(string: item.placeholder, font: textFont, textColor: theme.list.itemPlaceholderTextColor) let attributedPlaceholder = NSAttributedString(string: item.placeholder, font: textFont, textColor: theme.list.itemPlaceholderTextColor)
if !(self.textField.textField.attributedPlaceholder?.isEqual(to: attributedPlaceholder) ?? false) { if !(self.textField.textField.attributedPlaceholder?.isEqual(to: attributedPlaceholder) ?? false) {
self.textField.textField.attributedPlaceholder = attributedPlaceholder self.textField.textField.attributedPlaceholder = attributedPlaceholder

View File

@ -226,7 +226,10 @@ final class JoinLinkPreviewControllerNode: ViewControllerTracingNode, UIScrollVi
let cleanInsets = layout.insets(options: [.statusBar]) let cleanInsets = layout.insets(options: [.statusBar])
insets.top = max(10.0, insets.top) insets.top = max(10.0, insets.top)
let bottomInset: CGFloat = 10.0 + cleanInsets.bottom var bottomInset: CGFloat = 10.0 + cleanInsets.bottom
if insets.bottom > 0 {
bottomInset -= 12.0
}
let buttonHeight: CGFloat = 57.0 let buttonHeight: CGFloat = 57.0
let sectionSpacing: CGFloat = 8.0 let sectionSpacing: CGFloat = 8.0
let titleAreaHeight: CGFloat = 64.0 let titleAreaHeight: CGFloat = 64.0
@ -239,7 +242,7 @@ final class JoinLinkPreviewControllerNode: ViewControllerTracingNode, UIScrollVi
let contentContainerFrame = CGRect(origin: CGPoint(x: sideInset, y: insets.top), size: CGSize(width: width, height: maximumContentHeight)) let contentContainerFrame = CGRect(origin: CGPoint(x: sideInset, y: insets.top), size: CGSize(width: width, height: maximumContentHeight))
let contentFrame = contentContainerFrame.insetBy(dx: 0.0, dy: 0.0) let contentFrame = contentContainerFrame.insetBy(dx: 0.0, dy: 0.0)
var bottomGridInset = buttonHeight let bottomGridInset = buttonHeight
self.containerLayout = (layout, navigationBarHeight, bottomGridInset) self.containerLayout = (layout, navigationBarHeight, bottomGridInset)
self.scheduledLayoutTransitionRequest = nil self.scheduledLayoutTransitionRequest = nil
@ -272,7 +275,10 @@ final class JoinLinkPreviewControllerNode: ViewControllerTracingNode, UIScrollVi
insets.top = max(10.0, insets.top) insets.top = max(10.0, insets.top)
let cleanInsets = layout.insets(options: [.statusBar]) let cleanInsets = layout.insets(options: [.statusBar])
let bottomInset: CGFloat = 10.0 + cleanInsets.bottom var bottomInset: CGFloat = 10.0 + cleanInsets.bottom
if insets.bottom > 0 {
bottomInset -= 12.0
}
let buttonHeight: CGFloat = 57.0 let buttonHeight: CGFloat = 57.0
let sectionSpacing: CGFloat = 8.0 let sectionSpacing: CGFloat = 8.0

View File

@ -126,7 +126,7 @@ func legacyLocationController(message: Message, mapMedia: TelegramMediaMap, acco
let presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 } let presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 }
let legacyController = LegacyController(presentation: .navigation, theme: presentationData.theme, presentationData: presentationData) let legacyController = LegacyController(presentation: modal ? .modal(animateIn: true) : .navigation, theme: presentationData.theme, presentationData: presentationData)
let legacyMessage = makeLegacyMessage(message) let legacyMessage = makeLegacyMessage(message)

View File

@ -30,6 +30,7 @@ func legacyLocationPickerController(account: Account, selfPeer: Peer, peer: Peer
legacyController?.dismiss() legacyController?.dismiss()
}, rootController: nil) }, rootController: nil)
legacyController.bind(controller: navigationController) legacyController.bind(controller: navigationController)
legacyController.supportedOrientations = ViewControllerSupportedOrientations(regularSize: .all, compactSize: .portrait)
controller.locationPicked = { [weak legacyController] coordinate, venue in controller.locationPicked = { [weak legacyController] coordinate, venue in
sendLocation(coordinate, venue.flatMap { venue in sendLocation(coordinate, venue.flatMap { venue in
return MapVenue(title: venue.title, address: venue.address, provider: venue.provider, id: venue.venueId, type: venue.type) return MapVenue(title: venue.title, address: venue.address, provider: venue.provider, id: venue.venueId, type: venue.type)

View File

@ -1555,19 +1555,19 @@ enum SecureIdDocumentFormEntry: FormControllerEntry {
} }
return FormControllerHeaderItem(text: text) return FormControllerHeaderItem(text: text)
case let .identifier(value, error): case let .identifier(value, error):
return FormControllerTextInputItem(title: strings.Passport_Identity_DocumentNumber, text: value, placeholder: strings.Passport_Identity_DocumentNumberPlaceholder, error: error, textUpdated: { text in return FormControllerTextInputItem(title: strings.Passport_Identity_DocumentNumber, text: value, placeholder: strings.Passport_Identity_DocumentNumberPlaceholder, type: .regular(capitalization: .words, autocorrection: false), error: error, textUpdated: { text in
params.updateText(.identifier, text) params.updateText(.identifier, text)
}) })
case let .firstName(value, error): case let .firstName(value, error):
return FormControllerTextInputItem(title: strings.Passport_Identity_Name, text: value, placeholder: strings.Passport_Identity_NamePlaceholder, error: error, textUpdated: { text in return FormControllerTextInputItem(title: strings.Passport_Identity_Name, text: value, placeholder: strings.Passport_Identity_NamePlaceholder, type: .latin, error: error, textUpdated: { text in
params.updateText(.firstName, text) params.updateText(.firstName, text)
}) })
case let .middleName(value, error): case let .middleName(value, error):
return FormControllerTextInputItem(title: strings.Passport_Identity_MiddleName, text: value, placeholder: strings.Passport_Identity_MiddleNamePlaceholder, error: error, textUpdated: { text in return FormControllerTextInputItem(title: strings.Passport_Identity_MiddleName, text: value, placeholder: strings.Passport_Identity_MiddleNamePlaceholder, type: .latin, error: error, textUpdated: { text in
params.updateText(.middleName, text) params.updateText(.middleName, text)
}) })
case let .lastName(value, error): case let .lastName(value, error):
return FormControllerTextInputItem(title: strings.Passport_Identity_Surname, text: value, placeholder: strings.Passport_Identity_SurnamePlaceholder, error: error, textUpdated: { text in return FormControllerTextInputItem(title: strings.Passport_Identity_Surname, text: value, placeholder: strings.Passport_Identity_SurnamePlaceholder, type: .latin, error: error, textUpdated: { text in
params.updateText(.lastName, text) params.updateText(.lastName, text)
}) })
case let .nativeInfoHeader(language): case let .nativeInfoHeader(language):
@ -1579,23 +1579,23 @@ enum SecureIdDocumentFormEntry: FormControllerEntry {
} }
return FormControllerHeaderItem(text: title) return FormControllerHeaderItem(text: title)
case let .nativeFirstName(value, error): case let .nativeFirstName(value, error):
return FormControllerTextInputItem(title: strings.Passport_Identity_Name, text: value, placeholder: strings.Passport_Identity_NamePlaceholder, error: error, textUpdated: { text in return FormControllerTextInputItem(title: strings.Passport_Identity_Name, text: value, placeholder: strings.Passport_Identity_NamePlaceholder, type: .regular(capitalization: .words, autocorrection: false), error: error, textUpdated: { text in
params.updateText(.nativeFirstName, text) params.updateText(.nativeFirstName, text)
}) })
case let .nativeMiddleName(value, error): case let .nativeMiddleName(value, error):
return FormControllerTextInputItem(title: strings.Passport_Identity_MiddleName, text: value, placeholder: strings.Passport_Identity_MiddleNamePlaceholder, error: error, textUpdated: { text in return FormControllerTextInputItem(title: strings.Passport_Identity_MiddleName, text: value, placeholder: strings.Passport_Identity_MiddleNamePlaceholder, type: .regular(capitalization: .words, autocorrection: false), error: error, textUpdated: { text in
params.updateText(.nativeMiddleName, text) params.updateText(.nativeMiddleName, text)
}) })
case let .nativeLastName(value, error): case let .nativeLastName(value, error):
return FormControllerTextInputItem(title: strings.Passport_Identity_Surname, text: value, placeholder: strings.Passport_Identity_SurnamePlaceholder, error: error, textUpdated: { text in return FormControllerTextInputItem(title: strings.Passport_Identity_Surname, text: value, placeholder: strings.Passport_Identity_SurnamePlaceholder, type: .regular(capitalization: .words, autocorrection: false), error: error, textUpdated: { text in
params.updateText(.nativeLastName, text) params.updateText(.nativeLastName, text)
}) })
case let .nativeInfo(language): case let .nativeInfo(language):
let text: String let text: String
if !language.isEmpty, let value = strings.dict["Passport.Language.\(language)"] { if !language.isEmpty, let _ = strings.dict["Passport.Language.\(language)"] {
text = strings.Passport_Identity_NativeNameGenericHelp(value).0.uppercased()
} else {
text = strings.Passport_Identity_NativeNameHelp text = strings.Passport_Identity_NativeNameHelp
} else {
text = strings.Passport_Identity_NativeNameGenericHelp("").0
} }
return FormControllerTextItem(text: text) return FormControllerTextItem(text: text)
case let .gender(value, error): case let .gender(value, error):
@ -1632,23 +1632,23 @@ enum SecureIdDocumentFormEntry: FormControllerEntry {
params.deleteValue() params.deleteValue()
}) })
case let .street1(value, error): case let .street1(value, error):
return FormControllerTextInputItem(title: strings.Passport_Address_Street, text: value, placeholder: strings.Passport_Address_Street1Placeholder, error: error, textUpdated: { text in return FormControllerTextInputItem(title: strings.Passport_Address_Street, text: value, placeholder: strings.Passport_Address_Street1Placeholder, type: .regular(capitalization: .words, autocorrection: false), error: error, textUpdated: { text in
params.updateText(.street1, text) params.updateText(.street1, text)
}) })
case let .street2(value, error): case let .street2(value, error):
return FormControllerTextInputItem(title: "", text: value, placeholder: strings.Passport_Address_Street2Placeholder, error: error, textUpdated: { text in return FormControllerTextInputItem(title: "", text: value, placeholder: strings.Passport_Address_Street2Placeholder, type: .regular(capitalization: .words, autocorrection: false), error: error, textUpdated: { text in
params.updateText(.street2, text) params.updateText(.street2, text)
}) })
case let .city(value, error): case let .city(value, error):
return FormControllerTextInputItem(title: strings.Passport_Address_City, text: value, placeholder: strings.Passport_Address_CityPlaceholder, error: error, textUpdated: { text in return FormControllerTextInputItem(title: strings.Passport_Address_City, text: value, placeholder: strings.Passport_Address_CityPlaceholder, type: .regular(capitalization: .words, autocorrection: false), error: error, textUpdated: { text in
params.updateText(.city, text) params.updateText(.city, text)
}) })
case let .state(value, error): case let .state(value, error):
return FormControllerTextInputItem(title: strings.Passport_Address_Region, text: value, placeholder: strings.Passport_Address_RegionPlaceholder, error: error, textUpdated: { text in return FormControllerTextInputItem(title: strings.Passport_Address_Region, text: value, placeholder: strings.Passport_Address_RegionPlaceholder, type: .regular(capitalization: .words, autocorrection: false), error: error, textUpdated: { text in
params.updateText(.state, text) params.updateText(.state, text)
}) })
case let .postcode(value, error): case let .postcode(value, error):
return FormControllerTextInputItem(title: strings.Passport_Address_Postcode, text: value, placeholder: strings.Passport_Address_PostcodePlaceholder, error: error, textUpdated: { text in return FormControllerTextInputItem(title: strings.Passport_Address_Postcode, text: value, placeholder: strings.Passport_Address_PostcodePlaceholder, type: .regular(capitalization: .allCharacters, autocorrection: false), error: error, textUpdated: { text in
params.updateText(.postcode, text) params.updateText(.postcode, text)
}) })
case .requestedDocumentsHeader: case .requestedDocumentsHeader:
@ -1883,10 +1883,26 @@ final class SecureIdDocumentFormControllerNode: FormControllerNode<SecureIdDocum
strongSelf.present(controller, ViewControllerPresentationArguments(presentationAnimation: .modalSheet)) strongSelf.present(controller, ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
case let .date(current, field): case let .date(current, field):
var emptyTitle: String? var emptyTitle: String?
var minimumDate: Date? = nil
var maximumDate: Date? = nil
let calendar = Calendar(identifier: .gregorian)
let now = Date()
if case .expiry = field { if case .expiry = field {
emptyTitle = strings.Passport_Identity_DoesNotExpire emptyTitle = strings.Passport_Identity_DoesNotExpire
var components = calendar.dateComponents([.year, .month, .day], from: now)
if let year = components.year {
components.year = year - 18
components.hour = 0
components.minute = 0
maximumDate = calendar.date(from: components)
} }
let controller = DateSelectionActionSheetController(theme: theme, strings: strings, currentValue: current ?? Int32(Date().timeIntervalSince1970), emptyTitle: emptyTitle, applyValue: { value in } else if case .birthdate = field {
var deltaComponents = DateComponents()
deltaComponents.month = 6
minimumDate = calendar.date(byAdding: deltaComponents, to: now)
}
let controller = DateSelectionActionSheetController(theme: theme, strings: strings, currentValue: current ?? Int32(Date().timeIntervalSince1970), minimumDate: minimumDate, maximumDate: maximumDate, emptyTitle: emptyTitle, applyValue: { value in
if let strongSelf = self, var innerState = strongSelf.innerState { if let strongSelf = self, var innerState = strongSelf.innerState {
innerState.documentState.updateDateField(type: field, value: value.flatMap(SecureIdDate.init)) innerState.documentState.updateDateField(type: field, value: value.flatMap(SecureIdDate.init))
var valueKey: SecureIdValueKey? var valueKey: SecureIdValueKey?

View File

@ -509,17 +509,17 @@ enum SecureIdPlaintextFormEntry: FormControllerEntry {
case .numberInputInfo: case .numberInputInfo:
return FormControllerTextItem(text: strings.Passport_Phone_Help) return FormControllerTextItem(text: strings.Passport_Phone_Help)
case let .numberCode(code): case let .numberCode(code):
return FormControllerTextInputItem(title: strings.ChangePhoneNumberCode_CodePlaceholder, text: code, placeholder: strings.ChangePhoneNumberCode_CodePlaceholder, textUpdated: { value in return FormControllerTextInputItem(title: strings.ChangePhoneNumberCode_CodePlaceholder, text: code, placeholder: strings.ChangePhoneNumberCode_CodePlaceholder, type: .number, textUpdated: { value in
params.updateTextField(.code, value) params.updateTextField(.code, value)
}) })
case .numberVerifyInfo: case .numberVerifyInfo:
return FormControllerTextItem(text: strings.ChangePhoneNumberCode_Help) return FormControllerTextItem(text: strings.ChangePhoneNumberCode_Help)
case let .emailAddress(address): case let .emailAddress(address):
return FormControllerTextInputItem(title: strings.TwoStepAuth_Email, text: address, placeholder: strings.TwoStepAuth_Email, textUpdated: { value in return FormControllerTextInputItem(title: strings.TwoStepAuth_Email, text: address, placeholder: strings.TwoStepAuth_Email, type: .email, textUpdated: { value in
params.updateTextField(.email, value) params.updateTextField(.email, value)
}) })
case let .emailCode(code): case let .emailCode(code):
return FormControllerTextInputItem(title: strings.TwoStepAuth_RecoveryCode, text: code, placeholder: strings.TwoStepAuth_RecoveryCode, textUpdated: { value in return FormControllerTextInputItem(title: strings.TwoStepAuth_RecoveryCode, text: code, placeholder: strings.TwoStepAuth_RecoveryCode, type: .number, textUpdated: { value in
params.updateTextField(.code, value) params.updateTextField(.code, value)
}) })
case .emailVerifyInfo: case .emailVerifyInfo:
@ -563,10 +563,10 @@ final class SecureIdPlaintextFormControllerNode: FormControllerNode<SecureIdPlai
guard let strongSelf = self else { guard let strongSelf = self else {
return return
} }
let controller = AuthorizationSequenceCountrySelectionController(strings: strings, theme: AuthorizationSequenceCountrySelectionTheme(presentationTheme: strongSelf.theme), displayCodes: false) let controller = AuthorizationSequenceCountrySelectionController(strings: strings, theme: AuthorizationSequenceCountrySelectionTheme(presentationTheme: strongSelf.theme), displayCodes: true)
controller.completeWithCountryCode = { _, id in controller.completeWithCountryCode = { code, _ in
if let strongSelf = self, var innerState = strongSelf.innerState { if let strongSelf = self, var innerState = strongSelf.innerState {
innerState.data.updateTextField(type: .countryCode, value: "+\(id)") innerState.data.updateTextField(type: .countryCode, value: "+\(code)")
strongSelf.updateInnerState(transition: .immediate, with: innerState) strongSelf.updateInnerState(transition: .immediate, with: innerState)
} }
} }

View File

@ -318,7 +318,11 @@ final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate
let cleanInsets = layout.insets(options: [.statusBar]) let cleanInsets = layout.insets(options: [.statusBar])
insets.top = max(10.0, insets.top) insets.top = max(10.0, insets.top)
let bottomInset: CGFloat = 10.0 + cleanInsets.bottom var bottomInset: CGFloat = 10.0 + cleanInsets.bottom
if insets.bottom > 0 {
bottomInset -= 12.0
}
let buttonHeight: CGFloat = 57.0 let buttonHeight: CGFloat = 57.0
let sectionSpacing: CGFloat = 8.0 let sectionSpacing: CGFloat = 8.0
let titleAreaHeight: CGFloat = 64.0 let titleAreaHeight: CGFloat = 64.0
@ -378,7 +382,10 @@ final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate
insets.top = max(10.0, insets.top) insets.top = max(10.0, insets.top)
let cleanInsets = layout.insets(options: [.statusBar]) let cleanInsets = layout.insets(options: [.statusBar])
let bottomInset: CGFloat = 10.0 + cleanInsets.bottom var bottomInset: CGFloat = 10.0 + cleanInsets.bottom
if insets.bottom > 0 {
bottomInset -= 12.0
}
let buttonHeight: CGFloat = 57.0 let buttonHeight: CGFloat = 57.0
let sectionSpacing: CGFloat = 8.0 let sectionSpacing: CGFloat = 8.0

View File

@ -245,7 +245,11 @@ final class StickerPackPreviewControllerNode: ViewControllerTracingNode, UIScrol
transition.updateFrame(node: self.dimNode, frame: CGRect(origin: CGPoint(), size: layout.size)) transition.updateFrame(node: self.dimNode, frame: CGRect(origin: CGPoint(), size: layout.size))
let bottomInset: CGFloat = 10.0 + cleanInsets.bottom var bottomInset: CGFloat = 10.0 + cleanInsets.bottom
if insets.bottom > 0 {
bottomInset -= 12.0
}
let buttonHeight: CGFloat = 57.0 let buttonHeight: CGFloat = 57.0
let sectionSpacing: CGFloat = 8.0 let sectionSpacing: CGFloat = 8.0
let titleAreaHeight: CGFloat = 51.0 let titleAreaHeight: CGFloat = 51.0
@ -352,7 +356,11 @@ final class StickerPackPreviewControllerNode: ViewControllerTracingNode, UIScrol
insets.top = max(10.0, insets.top) insets.top = max(10.0, insets.top)
let cleanInsets = layout.insets(options: [.statusBar]) let cleanInsets = layout.insets(options: [.statusBar])
let bottomInset: CGFloat = 10.0 + cleanInsets.bottom var bottomInset: CGFloat = 10.0 + cleanInsets.bottom
if insets.bottom > 0 {
bottomInset -= 12.0
}
let buttonHeight: CGFloat = 57.0 let buttonHeight: CGFloat = 57.0
let sectionSpacing: CGFloat = 8.0 let sectionSpacing: CGFloat = 8.0
let titleAreaHeight: CGFloat = 51.0 let titleAreaHeight: CGFloat = 51.0

View File

@ -44,7 +44,7 @@ private enum TwoStepVerificationPasswordEntryEntry: ItemListNodeEntry {
case hintTitle(PresentationTheme, String) case hintTitle(PresentationTheme, String)
case hintEntry(PresentationTheme, String) case hintEntry(PresentationTheme, String)
case emailEntry(PresentationTheme, String) case emailEntry(PresentationTheme, PresentationStrings, String)
case emailInfo(PresentationTheme, String) case emailInfo(PresentationTheme, String)
var section: ItemListSectionId { var section: ItemListSectionId {
@ -94,8 +94,8 @@ private enum TwoStepVerificationPasswordEntryEntry: ItemListNodeEntry {
} else { } else {
return false return false
} }
case let .emailEntry(lhsTheme, lhsText): case let .emailEntry(lhsTheme, lhsStrings, lhsText):
if case let .emailEntry(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText { if case let .emailEntry(rhsTheme, rhsStrings, rhsText) = rhs, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsText == rhsText {
return true return true
} else { } else {
return false return false
@ -131,8 +131,8 @@ private enum TwoStepVerificationPasswordEntryEntry: ItemListNodeEntry {
}, action: { }, action: {
arguments.next() arguments.next()
}) })
case let .emailEntry(theme, text): case let .emailEntry(theme, strings, text):
return ItemListSingleLineInputItem(theme: theme, title: NSAttributedString(string: "E-Mail", textColor: .black), text: text, placeholder: "", type: .email, spacing: 10.0, tag: TwoStepVerificationPasswordEntryTag.input, sectionId: self.section, textUpdated: { updatedText in return ItemListSingleLineInputItem(theme: theme, title: NSAttributedString(string: strings.TwoStepAuth_Email, textColor: .black), text: text, placeholder: "", type: .email, spacing: 10.0, tag: TwoStepVerificationPasswordEntryTag.input, sectionId: self.section, textUpdated: { updatedText in
arguments.updateEntryText(updatedText) arguments.updateEntryText(updatedText)
}, action: { }, action: {
arguments.next() arguments.next()
@ -235,7 +235,7 @@ private func twoStepVerificationPasswordEntryControllerEntries(presentationData:
entries.append(.hintTitle(presentationData.theme, presentationData.strings.TwoStepAuth_SetupHint)) entries.append(.hintTitle(presentationData.theme, presentationData.strings.TwoStepAuth_SetupHint))
entries.append(.hintEntry(presentationData.theme, text)) entries.append(.hintEntry(presentationData.theme, text))
case let .email(_, _, text): case let .email(_, _, text):
entries.append(.emailEntry(presentationData.theme, text)) entries.append(.emailEntry(presentationData.theme, presentationData.strings, text))
entries.append(.emailInfo(presentationData.theme, presentationData.strings.TwoStepAuth_EmailHelp)) entries.append(.emailInfo(presentationData.theme, presentationData.strings.TwoStepAuth_EmailHelp))
} }
@ -341,11 +341,11 @@ func twoStepVerificationPasswordEntryController(account: Account, mode: TwoStepV
let alertText: String let alertText: String
switch error { switch error {
case .generic: case .generic:
alertText = "An error occurred." alertText = presentationData.strings.Login_UnknownError
case .invalidEmail: case .invalidEmail:
alertText = "Please enter valid e-mail address." alertText = presentationData.strings.TwoStepAuth_EmailInvalid
} }
presentControllerImpl?(standardTextAlertController(theme: AlertControllerTheme(presentationTheme: presentationData.theme), title: nil, text: alertText, actions: [TextAlertAction(type: .defaultAction, title: "OK", action: {})]), ViewControllerPresentationArguments(presentationAnimation: .modalSheet)) presentControllerImpl?(standardTextAlertController(theme: AlertControllerTheme(presentationTheme: presentationData.theme), title: nil, text: alertText, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
})) }))
case let .setupEmail(password): case let .setupEmail(password):
updatePasswordDisposable.set((updateTwoStepVerificationEmail(account: account, currentPassword: password, updatedEmail: email) |> deliverOnMainQueue).start(next: { update in updatePasswordDisposable.set((updateTwoStepVerificationEmail(account: account, currentPassword: password, updatedEmail: email) |> deliverOnMainQueue).start(next: { update in
@ -366,16 +366,16 @@ func twoStepVerificationPasswordEntryController(account: Account, mode: TwoStepV
let alertText: String let alertText: String
switch error { switch error {
case .generic: case .generic:
alertText = "An error occurred." alertText = presentationData.strings.Login_UnknownError
case .invalidEmail: case .invalidEmail:
alertText = "Please enter valid e-mail address." alertText = presentationData.strings.TwoStepAuth_EmailInvalid
} }
presentControllerImpl?(standardTextAlertController(theme: AlertControllerTheme(presentationTheme: presentationData.theme), title: nil, text: alertText, actions: [TextAlertAction(type: .defaultAction, title: "OK", action: {})]), ViewControllerPresentationArguments(presentationAnimation: .modalSheet)) presentControllerImpl?(standardTextAlertController(theme: AlertControllerTheme(presentationTheme: presentationData.theme), title: nil, text: alertText, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
})) }))
} }
} else if invalidReentry { } else if invalidReentry {
let presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 } let presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 }
presentControllerImpl?(standardTextAlertController(theme: AlertControllerTheme(presentationTheme: presentationData.theme), title: nil, text: "Passwords don't match.\nPlease try again.", actions: [TextAlertAction(type: .defaultAction, title: "OK", action: {})]), ViewControllerPresentationArguments(presentationAnimation: .modalSheet)) presentControllerImpl?(standardTextAlertController(theme: AlertControllerTheme(presentationTheme: presentationData.theme), title: nil, text: presentationData.strings.TwoStepAuth_SetupPasswordConfirmFailed, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
} }
} }

View File

@ -237,7 +237,7 @@ private func twoStepVerificationUnlockSettingsControllerEntries(presentationData
} else { } else {
entries.append(.pendingEmailInfo(presentationData.theme, presentationData.strings.TwoStepAuth_ConfirmationText + "\n\n\(pendingEmailPattern)\n\n[" + presentationData.strings.TwoStepAuth_ConfirmationAbort + "]()")) entries.append(.pendingEmailInfo(presentationData.theme, presentationData.strings.TwoStepAuth_ConfirmationText + "\n\n\(pendingEmailPattern)\n\n[" + presentationData.strings.TwoStepAuth_ConfirmationAbort + "]()"))
} }
case let .set(hint, _, _): case let .set(hint, _, _, _):
entries.append(.passwordEntry(presentationData.theme, presentationData.strings.TwoStepAuth_EnterPasswordPassword, state.passwordText)) entries.append(.passwordEntry(presentationData.theme, presentationData.strings.TwoStepAuth_EnterPasswordPassword, state.passwordText))
if hint.isEmpty { if hint.isEmpty {
entries.append(.passwordEntryInfo(presentationData.theme, presentationData.strings.TwoStepAuth_EnterPasswordHelp + "\n\n[" + presentationData.strings.TwoStepAuth_EnterPasswordForgot + "](forgot)")) entries.append(.passwordEntryInfo(presentationData.theme, presentationData.strings.TwoStepAuth_EnterPasswordHelp + "\n\n[" + presentationData.strings.TwoStepAuth_EnterPasswordForgot + "](forgot)"))
@ -246,7 +246,7 @@ private func twoStepVerificationUnlockSettingsControllerEntries(presentationData
} }
} }
} }
case let .manage(_, emailSet, pendingEmailPattern): case let .manage(_, emailSet, pendingEmailPattern, _):
entries.append(.changePassword(presentationData.theme, presentationData.strings.TwoStepAuth_ChangePassword)) entries.append(.changePassword(presentationData.theme, presentationData.strings.TwoStepAuth_ChangePassword))
entries.append(.turnPasswordOff(presentationData.theme, presentationData.strings.TwoStepAuth_RemovePassword)) entries.append(.turnPasswordOff(presentationData.theme, presentationData.strings.TwoStepAuth_RemovePassword))
entries.append(.setupRecoveryEmail(presentationData.theme, emailSet ? presentationData.strings.TwoStepAuth_ChangeEmail : presentationData.strings.TwoStepAuth_SetupEmail)) entries.append(.setupRecoveryEmail(presentationData.theme, emailSet ? presentationData.strings.TwoStepAuth_ChangeEmail : presentationData.strings.TwoStepAuth_SetupEmail))
@ -262,12 +262,12 @@ private func twoStepVerificationUnlockSettingsControllerEntries(presentationData
enum TwoStepVerificationUnlockSettingsControllerMode { enum TwoStepVerificationUnlockSettingsControllerMode {
case access case access
case manage(password: String, email: String, pendingEmailPattern: String) case manage(password: String, email: String, pendingEmailPattern: String, hasSecureValues: Bool)
} }
private enum TwoStepVerificationUnlockSettingsControllerData { private enum TwoStepVerificationUnlockSettingsControllerData {
case access(configuration: TwoStepVerificationConfiguration?) case access(configuration: TwoStepVerificationConfiguration?)
case manage(password: String, emailSet: Bool, pendingEmailPattern: String) case manage(password: String, emailSet: Bool, pendingEmailPattern: String, hasSecureValues: Bool)
} }
func twoStepVerificationUnlockSettingsController(account: Account, mode: TwoStepVerificationUnlockSettingsControllerMode) -> ViewController { func twoStepVerificationUnlockSettingsController(account: Account, mode: TwoStepVerificationUnlockSettingsControllerMode) -> ViewController {
@ -298,8 +298,8 @@ func twoStepVerificationUnlockSettingsController(account: Account, mode: TwoStep
switch mode { switch mode {
case .access: case .access:
dataPromise.set(.single(TwoStepVerificationUnlockSettingsControllerData.access(configuration: nil)) |> then(twoStepVerificationConfiguration(account: account) |> map { TwoStepVerificationUnlockSettingsControllerData.access(configuration: $0) })) dataPromise.set(.single(TwoStepVerificationUnlockSettingsControllerData.access(configuration: nil)) |> then(twoStepVerificationConfiguration(account: account) |> map { TwoStepVerificationUnlockSettingsControllerData.access(configuration: $0) }))
case let .manage(password, email, pendingEmailPattern): case let .manage(password, email, pendingEmailPattern, hasSecureValues):
dataPromise.set(.single(.manage(password: password, emailSet: !email.isEmpty, pendingEmailPattern: pendingEmailPattern))) dataPromise.set(.single(.manage(password: password, emailSet: !email.isEmpty, pendingEmailPattern: pendingEmailPattern, hasSecureValues: hasSecureValues)))
} }
let arguments = TwoStepVerificationUnlockSettingsControllerArguments(updatePasswordText: { updatedText in let arguments = TwoStepVerificationUnlockSettingsControllerArguments(updatePasswordText: { updatedText in
@ -313,7 +313,7 @@ func twoStepVerificationUnlockSettingsController(account: Account, mode: TwoStep
if let configuration = configuration { if let configuration = configuration {
let presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 } let presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 }
switch configuration { switch configuration {
case let .set(_, hasRecoveryEmail, _): case let .set(_, hasRecoveryEmail, _, _):
if hasRecoveryEmail { if hasRecoveryEmail {
updateState { updateState {
$0.withUpdatedChecking(true) $0.withUpdatedChecking(true)
@ -336,7 +336,7 @@ func twoStepVerificationUnlockSettingsController(account: Account, mode: TwoStep
presentControllerImpl?(standardTextAlertController(theme: AlertControllerTheme(presentationTheme: presentationData.theme), title: nil, text: presentationData.strings.Login_UnknownError, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), ViewControllerPresentationArguments(presentationAnimation: .modalSheet)) presentControllerImpl?(standardTextAlertController(theme: AlertControllerTheme(presentationTheme: presentationData.theme), title: nil, text: presentationData.strings.Login_UnknownError, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
})) }))
} else { } else {
presentControllerImpl?(standardTextAlertController(theme: AlertControllerTheme(presentationTheme: presentationData.theme), title: nil, text: "Since you haven't provided a recovery e-mail when setting up your password, your remaining options are either to remember your password or to reset your account.", actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), ViewControllerPresentationArguments(presentationAnimation: .modalSheet)) presentControllerImpl?(standardTextAlertController(theme: AlertControllerTheme(presentationTheme: presentationData.theme), title: nil, text: presentationData.strings.TwoStepAuth_RecoveryUnavailable, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
} }
case .notSet: case .notSet:
break break
@ -361,7 +361,7 @@ func twoStepVerificationUnlockSettingsController(account: Account, mode: TwoStep
if let pendingEmailPattern = updatedPassword.pendingEmailPattern { if let pendingEmailPattern = updatedPassword.pendingEmailPattern {
dataPromise.set(.single(TwoStepVerificationUnlockSettingsControllerData.access(configuration: TwoStepVerificationConfiguration.notSet(pendingEmailPattern: pendingEmailPattern)))) dataPromise.set(.single(TwoStepVerificationUnlockSettingsControllerData.access(configuration: TwoStepVerificationConfiguration.notSet(pendingEmailPattern: pendingEmailPattern))))
} else { } else {
dataPromise.set(.single(TwoStepVerificationUnlockSettingsControllerData.manage(password: updatedPassword.password, emailSet: false, pendingEmailPattern: ""))) dataPromise.set(.single(TwoStepVerificationUnlockSettingsControllerData.manage(password: updatedPassword.password, emailSet: false, pendingEmailPattern: "", hasSecureValues: false)))
} }
controller?.dismiss() controller?.dismiss()
} }
@ -370,21 +370,28 @@ func twoStepVerificationUnlockSettingsController(account: Account, mode: TwoStep
break break
} }
} }
case let .manage(password, emailSet, pendingEmailPattern): case let .manage(password, emailSet, pendingEmailPattern, hasSecureValues):
let result = Promise<TwoStepVerificationPasswordEntryResult?>() let result = Promise<TwoStepVerificationPasswordEntryResult?>()
let controller = twoStepVerificationPasswordEntryController(account: account, mode: .change(current: password), result: result) let controller = twoStepVerificationPasswordEntryController(account: account, mode: .change(current: password), result: result)
presentControllerImpl?(controller, ViewControllerPresentationArguments(presentationAnimation: .modalSheet)) presentControllerImpl?(controller, ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
setupResultDisposable.set((result.get() |> take(1) |> deliverOnMainQueue).start(next: { [weak controller] updatedPassword in setupResultDisposable.set((result.get() |> take(1) |> deliverOnMainQueue).start(next: { [weak controller] updatedPassword in
if let updatedPassword = updatedPassword { if let updatedPassword = updatedPassword {
dataPromise.set(.single(TwoStepVerificationUnlockSettingsControllerData.manage(password: updatedPassword.password, emailSet: emailSet, pendingEmailPattern: pendingEmailPattern))) dataPromise.set(.single(TwoStepVerificationUnlockSettingsControllerData.manage(password: updatedPassword.password, emailSet: emailSet, pendingEmailPattern: pendingEmailPattern, hasSecureValues: hasSecureValues)))
controller?.dismiss() controller?.dismiss()
} }
})) }))
} }
})) }))
}, openDisablePassword: { }, openDisablePassword: {
setupDisposable.set((dataPromise.get() |> take(1) |> deliverOnMainQueue).start(next: { data in
switch data {
case let .manage(_, _, _, hasSecureValues):
let presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 } let presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 }
presentControllerImpl?(standardTextAlertController(theme: AlertControllerTheme(presentationTheme: presentationData.theme), title: nil, text: "Are you sure you want to disable your password?", actions: [TextAlertAction(type: .defaultAction, title: "Cancel", action: {}), TextAlertAction(type: .genericAction, title: "OK", action: { var text = presentationData.strings.TwoStepAuth_PasswordRemoveConfirmation
if hasSecureValues {
text = presentationData.strings.TwoStepAuth_PasswordRemovePassportConfirmation
}
presentControllerImpl?(standardTextAlertController(theme: AlertControllerTheme(presentationTheme: presentationData.theme), title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: {
var disablePassword = false var disablePassword = false
updateState { state in updateState { state in
if state.checking { if state.checking {
@ -402,7 +409,7 @@ func twoStepVerificationUnlockSettingsController(account: Account, mode: TwoStep
switch data { switch data {
case .access: case .access:
return .complete() return .complete()
case let .manage(password, _, _): case let .manage(password, _, _, _):
return updateTwoStepVerificationPassword(network: account.network, currentPassword: password, updatedPassword: .none) return updateTwoStepVerificationPassword(network: account.network, currentPassword: password, updatedPassword: .none)
|> mapToSignal { _ -> Signal<Void, UpdateTwoStepVerificationPasswordError> in |> mapToSignal { _ -> Signal<Void, UpdateTwoStepVerificationPasswordError> in
return .complete() return .complete()
@ -421,18 +428,22 @@ func twoStepVerificationUnlockSettingsController(account: Account, mode: TwoStep
})) }))
} }
})]), ViewControllerPresentationArguments(presentationAnimation: .modalSheet)) })]), ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
default:
break
}
}))
}, openSetupEmail: { }, openSetupEmail: {
setupDisposable.set((dataPromise.get() |> take(1) |> deliverOnMainQueue).start(next: { data in setupDisposable.set((dataPromise.get() |> take(1) |> deliverOnMainQueue).start(next: { data in
switch data { switch data {
case .access: case .access:
break break
case let .manage(password, _, _): case let .manage(password, _, _, hasSecureValues):
let result = Promise<TwoStepVerificationPasswordEntryResult?>() let result = Promise<TwoStepVerificationPasswordEntryResult?>()
let controller = twoStepVerificationPasswordEntryController(account: account, mode: .setupEmail(password: password), result: result) let controller = twoStepVerificationPasswordEntryController(account: account, mode: .setupEmail(password: password), result: result)
presentControllerImpl?(controller, ViewControllerPresentationArguments(presentationAnimation: .modalSheet)) presentControllerImpl?(controller, ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
setupResultDisposable.set((result.get() |> take(1) |> deliverOnMainQueue).start(next: { [weak controller] updatedPassword in setupResultDisposable.set((result.get() |> take(1) |> deliverOnMainQueue).start(next: { [weak controller] updatedPassword in
if let updatedPassword = updatedPassword { if let updatedPassword = updatedPassword {
dataPromise.set(.single(TwoStepVerificationUnlockSettingsControllerData.manage(password: updatedPassword.password, emailSet: true, pendingEmailPattern: updatedPassword.pendingEmailPattern ?? ""))) dataPromise.set(.single(TwoStepVerificationUnlockSettingsControllerData.manage(password: updatedPassword.password, emailSet: true, pendingEmailPattern: updatedPassword.pendingEmailPattern ?? "", hasSecureValues: hasSecureValues)))
controller?.dismiss() controller?.dismiss()
} }
})) }))
@ -472,7 +483,7 @@ func twoStepVerificationUnlockSettingsController(account: Account, mode: TwoStep
switch configuration { switch configuration {
case .notSet: case .notSet:
break break
case .set: case let .set(_, _, _, hasSecureValues):
rightNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Common_Next), style: .bold, enabled: true, action: { rightNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Common_Next), style: .bold, enabled: true, action: {
var wasChecking = false var wasChecking = false
var password: String? var password: String?
@ -488,7 +499,7 @@ func twoStepVerificationUnlockSettingsController(account: Account, mode: TwoStep
$0.withUpdatedChecking(false) $0.withUpdatedChecking(false)
} }
replaceControllerImpl?(twoStepVerificationUnlockSettingsController(account: account, mode: .manage(password: password, email: settings.email, pendingEmailPattern: ""))) replaceControllerImpl?(twoStepVerificationUnlockSettingsController(account: account, mode: .manage(password: password, email: settings.email, pendingEmailPattern: "", hasSecureValues: hasSecureValues)))
}, error: { error in }, error: { error in
updateState { updateState {
$0.withUpdatedChecking(false) $0.withUpdatedChecking(false)
@ -506,7 +517,7 @@ func twoStepVerificationUnlockSettingsController(account: Account, mode: TwoStep
text = presentationData.strings.Login_UnknownError text = presentationData.strings.Login_UnknownError
} }
presentControllerImpl?(standardTextAlertController(theme: AlertControllerTheme(presentationTheme: presentationData.theme), title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: "OK", action: {})]), ViewControllerPresentationArguments(presentationAnimation: .modalSheet)) presentControllerImpl?(standardTextAlertController(theme: AlertControllerTheme(presentationTheme: presentationData.theme), title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
})) }))
} }
}) })