Merge branch 'master' of github.com:peter-iakovlev/TelegramUI

This commit is contained in:
Ilya Laktyushin 2018-09-14 18:15:39 +01:00
commit c2149ecd2e
7 changed files with 2417 additions and 2205 deletions

View File

@ -90,7 +90,7 @@ public class InviteContactsController: ViewController, MFMessageComposeViewContr
self.contactsNode.requestShareTelegram = { [weak self] in
if let strongSelf = self {
let url = strongSelf.presentationData.strings.InviteText_URL
var body = strongSelf.presentationData.strings.InviteText_SingleContact(url).0
let body = strongSelf.presentationData.strings.InviteText_SingleContact(url).0
let shareController = ShareController(account: strongSelf.account, subject: .text(body), externalShare: true, immediateExternalShare: true)
strongSelf.present(shareController, in: .window(.root))
@ -110,8 +110,8 @@ public class InviteContactsController: ViewController, MFMessageComposeViewContr
let url = strongSelf.presentationData.strings.InviteText_URL
var body = strongSelf.presentationData.strings.InviteText_SingleContact(url).0
if numbers.count == 1, numbers[0].1 > 0 {
body = strongSelf.presentationData.strings.InviteText_ContactsCount(numbers[0].1)
body = body.replacingOccurrences(of: "(null)", with: url)
body = strongSelf.presentationData.strings.InviteText_ContactsCountText(numbers[0].1)
body = body.replacingOccurrences(of: "{url}", with: url)
}
composer.body = body
strongSelf.composer = composer

View File

@ -340,18 +340,18 @@ final class InviteContactsControllerNode: ASDisplayNode {
self.addSubnode(self.countPanelNode)
self.presentationDataDisposable = (account.telegramApplicationContext.presentationData
|> deliverOnMainQueue).start(next: { [weak self] presentationData in
if let strongSelf = self {
let previousTheme = strongSelf.presentationData.theme
let previousStrings = strongSelf.presentationData.strings
|> deliverOnMainQueue).start(next: { [weak self] presentationData in
if let strongSelf = self {
let previousTheme = strongSelf.presentationData.theme
let previousStrings = strongSelf.presentationData.strings
strongSelf.presentationData = presentationData
strongSelf.presentationData = presentationData
if previousTheme !== presentationData.theme || previousStrings !== presentationData.strings {
strongSelf.updateThemeAndStrings()
}
if previousTheme !== presentationData.theme || previousStrings !== presentationData.strings {
strongSelf.updateThemeAndStrings()
}
})
}
})
let account = self.account
var firstTime: Int32 = 1

File diff suppressed because it is too large Load Diff

View File

@ -299,6 +299,10 @@ final class SecureIdAuthControllerNode: ViewControllerTracingNode {
self?.interaction.openUrl(url)
}, openMention: { [weak self] mention in
self?.interaction.openMention(mention)
}, requestLayout: { [weak self] in
if let strongSelf = self, let (layout, navigationHeight) = strongSelf.validLayout {
strongSelf.containerLayoutUpdated(layout, navigationBarHeight: navigationHeight, transition: .immediate)
}
})
contentNode = current
}
@ -363,6 +367,10 @@ final class SecureIdAuthControllerNode: ViewControllerTracingNode {
self?.openListField(field)
}, deleteAll: { [weak self] in
self?.deleteAllValues()
}, requestLayout: { [weak self] in
if let strongSelf = self, let (layout, navigationHeight) = strongSelf.validLayout {
strongSelf.containerLayoutUpdated(layout, navigationBarHeight: navigationHeight, transition: .immediate)
}
})
current.updateValues(values)
contentNode = current

View File

@ -15,9 +15,12 @@ final class SecureIdAuthFormContentNode: ASDisplayNode, SecureIdAuthContentNode,
private let headerNode: ImmediateTextNode
private let textNode: ImmediateTextNode
private let requestLayout: () -> Void
private var validLayout: CGFloat?
init(theme: PresentationTheme, strings: PresentationStrings, peer: Peer, privacyPolicyUrl: String?, form: SecureIdForm, openField: @escaping (SecureIdParsedRequestedFormField) -> Void, openURL: @escaping (String) -> Void, openMention: @escaping (TelegramPeerMention) -> Void) {
init(theme: PresentationTheme, strings: PresentationStrings, peer: Peer, privacyPolicyUrl: String?, form: SecureIdForm, openField: @escaping (SecureIdParsedRequestedFormField) -> Void, openURL: @escaping (String) -> Void, openMention: @escaping (TelegramPeerMention) -> Void, requestLayout: @escaping () -> Void) {
self.requestLayout = requestLayout
self.requestedFields = form.requestedFields
self.fieldBackgroundNode = ASDisplayNode()
self.fieldBackgroundNode.isLayerBacked = true
@ -91,6 +94,7 @@ final class SecureIdAuthFormContentNode: ASDisplayNode, SecureIdAuthContentNode,
}
index += 1
}
self.requestLayout()
}
func updateLayout(width: CGFloat, transition: ContainedViewLayoutTransition) -> SecureIdAuthContentLayout {

View File

@ -15,9 +15,10 @@ final class SecureIdAuthListContentNode: ASDisplayNode, SecureIdAuthContentNode,
private let deleteItem: FormControllerActionItem
private let deleteNode: FormControllerActionItemNode
private let requestLayout: () -> Void
private var validLayout: CGFloat?
init(theme: PresentationTheme, strings: PresentationStrings, openField: @escaping (SecureIdAuthListContentField) -> Void, deleteAll: @escaping () -> Void) {
init(theme: PresentationTheme, strings: PresentationStrings, openField: @escaping (SecureIdAuthListContentField) -> Void, deleteAll: @escaping () -> Void, requestLayout: @escaping () -> Void) {
self.theme = theme
self.strings = strings
@ -50,6 +51,8 @@ final class SecureIdAuthListContentNode: ASDisplayNode, SecureIdAuthContentNode,
})
self.deleteNode = self.deleteItem.node() as! FormControllerActionItemNode
self.requestLayout = requestLayout
super.init()
self.addSubnode(self.headerNode)
@ -62,6 +65,8 @@ final class SecureIdAuthListContentNode: ASDisplayNode, SecureIdAuthContentNode,
for fieldNode in self.fieldNodes {
fieldNode.updateValues(values)
}
self.requestLayout()
}
func updateLayout(width: CGFloat, transition: ContainedViewLayoutTransition) -> SecureIdAuthContentLayout {

View File

@ -420,6 +420,13 @@ struct SecureIdDocumentFormState: FormControllerInnerState {
}
result.append(.entry(SecureIdDocumentFormEntry.infoHeader(.identity)))
let previousValue: SecureIdValueWithContext? = self.previousValues[.personalDetails]
let valueErrorKey: SecureIdValueContentErrorKey = .value(.personalDetails)
if let previousValue = previousValue {
maybeAddError(key: valueErrorKey, value: previousValue, entries: &result, errorIndex: &errorIndex)
}
result.append(.entry(SecureIdDocumentFormEntry.firstName(details.firstName, self.previousValues[.personalDetails]?.errors[.field(.personalDetails(.firstName))])))
result.append(.entry(SecureIdDocumentFormEntry.middleName(details.middleName, self.previousValues[.personalDetails]?.errors[.field(.personalDetails(.middleName))])))
result.append(.entry(SecureIdDocumentFormEntry.lastName(details.lastName, self.previousValues[.personalDetails]?.errors[.field(.personalDetails(.lastName))])))
@ -448,23 +455,38 @@ struct SecureIdDocumentFormState: FormControllerInnerState {
result.append(.entry(SecureIdDocumentFormEntry.infoHeader(.identity)))
}
let previousValue: SecureIdValueWithContext?
let valueErrorKey: SecureIdValueContentErrorKey
var identifierError: String?
var expiryDateError: String?
switch document.type {
case .passport:
previousValue = self.previousValues[.passport]
valueErrorKey = .value(.passport)
identifierError = self.previousValues[.passport]?.errors[.field(.passport(.documentId))]
expiryDateError = self.previousValues[.passport]?.errors[.field(.passport(.expiryDate))]
case .internalPassport:
previousValue = self.previousValues[.internalPassport]
valueErrorKey = .value(.internalPassport)
identifierError = self.previousValues[.internalPassport]?.errors[.field(.internalPassport(.documentId))]
expiryDateError = self.previousValues[.internalPassport]?.errors[.field(.internalPassport(.expiryDate))]
case .driversLicense:
previousValue = self.previousValues[.driversLicense]
valueErrorKey = .value(.driversLicense)
identifierError = self.previousValues[.driversLicense]?.errors[.field(.driversLicense(.documentId))]
expiryDateError = self.previousValues[.driversLicense]?.errors[.field(.driversLicense(.expiryDate))]
case .idCard:
previousValue = self.previousValues[.idCard]
valueErrorKey = .value(.idCard)
identifierError = self.previousValues[.idCard]?.errors[.field(.idCard(.documentId))]
expiryDateError = self.previousValues[.idCard]?.errors[.field(.idCard(.expiryDate))]
}
if let previousValue = previousValue {
maybeAddError(key: valueErrorKey, value: previousValue, entries: &result, errorIndex: &errorIndex)
}
result.append(.entry(SecureIdDocumentFormEntry.identifier(document.identifier, identifierError)))
result.append(.entry(SecureIdDocumentFormEntry.expiryDate(document.expiryDate, expiryDateError)))
}
@ -736,6 +758,12 @@ struct SecureIdDocumentFormState: FormControllerInnerState {
if let details = address.details {
result.append(.entry(SecureIdDocumentFormEntry.infoHeader(.address)))
let previousValue: SecureIdValueWithContext? = self.previousValues[.address]
let valueErrorKey: SecureIdValueContentErrorKey = .value(.address)
if let previousValue = previousValue {
maybeAddError(key: valueErrorKey, value: previousValue, entries: &result, errorIndex: &errorIndex)
}
result.append(.entry(SecureIdDocumentFormEntry.street1(details.street1, self.previousValues[.address]?.errors[.field(.address(.streetLine1))])))
result.append(.entry(SecureIdDocumentFormEntry.street2(details.street2, self.previousValues[.address]?.errors[.field(.address(.streetLine2))])))
result.append(.entry(SecureIdDocumentFormEntry.city(details.city, self.previousValues[.address]?.errors[.field(.address(.city))])))
@ -1189,6 +1217,38 @@ extension SecureIdDocumentFormState {
}
}
private func removeDocumentWithId(_ innerState: SecureIdDocumentFormState, id: SecureIdVerificationDocumentId) -> SecureIdDocumentFormState {
var innerState = innerState
if let selfieDocument = innerState.selfieDocument, selfieDocument.id == id {
innerState.selfieDocument = nil
}
if let frontSideDocument = innerState.frontSideDocument, frontSideDocument.id == id {
innerState.frontSideDocument = nil
}
if let backSideDocument = innerState.backSideDocument, backSideDocument.id == id {
innerState.backSideDocument = nil
}
for i in 0 ..< innerState.documents.count {
if innerState.documents[i].id == id {
innerState.documents.remove(at: i)
break
}
}
for i in 0 ..< innerState.translations.count {
if innerState.translations[i].id == id {
innerState.translations.remove(at: i)
break
}
}
return innerState
}
enum SecureIdDocumentFormEntryId: Hashable {
case scanYourPassport
case scanYourPassportInfo
@ -1892,7 +1952,7 @@ final class SecureIdDocumentFormControllerNode: FormControllerNode<SecureIdDocum
}
}, openDocument: { [weak self] document in
if let strongSelf = self {
strongSelf.presentGallery(document: document)
strongSelf.openDocument(document: document)
}
}, updateText: { [weak self] field, value in
if let strongSelf = self, var innerState = strongSelf.innerState {
@ -1908,6 +1968,18 @@ final class SecureIdDocumentFormControllerNode: FormControllerNode<SecureIdDocum
case .lastName:
valueKey = .personalDetails
errorKey = .field(.personalDetails(.lastName))
case .middleName:
valueKey = .personalDetails
errorKey = .field(.personalDetails(.middleName))
case .nativeFirstName:
valueKey = .personalDetails
errorKey = .field(.personalDetails(.firstNameNative))
case .nativeLastName:
valueKey = .personalDetails
errorKey = .field(.personalDetails(.lastNameNative))
case .nativeMiddleName:
valueKey = .personalDetails
errorKey = .field(.personalDetails(.middleNameNative))
case .identifier:
if let document = identity.document {
switch document.type {
@ -2202,7 +2274,7 @@ final class SecureIdDocumentFormControllerNode: FormControllerNode<SecureIdDocum
self.actionDisposable.dispose()
}
private func presentAssetPicker(_ type: AddFileTarget) {
private func presentAssetPicker(_ type: AddFileTarget, replaceDocumentId: SecureIdVerificationDocumentId? = nil) {
guard let validLayout = self.layoutState?.layout else {
return
}
@ -2244,45 +2316,77 @@ final class SecureIdDocumentFormControllerNode: FormControllerNode<SecureIdDocum
self?.view.endEditing(true)
self?.present(c, nil)
}, validLayout: validLayout, type: attachmentType, recognizeDocumentData: recognizeDocumentData, completion: { [weak self] resources, recognizedData in
self?.addDocuments(type: type, resources: resources, recognizedData: recognizedData)
self?.addDocuments(type: type, resources: resources, recognizedData: recognizedData, removeDocumentId: replaceDocumentId)
})
}
private func addDocuments(type: AddFileTarget, resources: [TelegramMediaResource], recognizedData: SecureIdRecognizedDocumentData?) {
private func addDocuments(type: AddFileTarget, resources: [TelegramMediaResource], recognizedData: SecureIdRecognizedDocumentData?, removeDocumentId: SecureIdVerificationDocumentId?) {
guard var innerState = self.innerState else {
return
}
switch type {
case .scan:
var addIndex = innerState.documents.count
if let removeDocumentId = removeDocumentId {
for i in 0 ..< innerState.documents.count {
if innerState.documents[i].id == removeDocumentId {
innerState.documents.remove(at: i)
addIndex = i
break
}
}
}
for resource in resources {
let id = arc4random64()
innerState.documents.append(.local(SecureIdVerificationLocalDocument(id: id, resource: SecureIdLocalImageResource(localId: id, source: resource), timestamp: Int32(Date().timeIntervalSince1970), state: .uploading(0.0))))
innerState.documents.insert(.local(SecureIdVerificationLocalDocument(id: id, resource: SecureIdLocalImageResource(localId: id, source: resource), timestamp: Int32(Date().timeIntervalSince1970), state: .uploading(0.0))), at: addIndex)
addIndex += 1
}
if innerState.documents.count > 20 {
innerState.documents = Array(innerState.documents[0 ..< 20])
}
case .selfie:
if let removeDocumentId = removeDocumentId {
innerState = removeDocumentWithId(innerState, id: removeDocumentId)
}
loop: for resource in resources {
let id = arc4random64()
innerState.selfieDocument = .local(SecureIdVerificationLocalDocument(id: id, resource: SecureIdLocalImageResource(localId: id, source: resource), timestamp: Int32(Date().timeIntervalSince1970), state: .uploading(0.0)))
break loop
}
case .frontSide:
if let removeDocumentId = removeDocumentId {
innerState = removeDocumentWithId(innerState, id: removeDocumentId)
}
loop: for resource in resources {
let id = arc4random64()
innerState.frontSideDocument = .local(SecureIdVerificationLocalDocument(id: id, resource: SecureIdLocalImageResource(localId: id, source: resource), timestamp: Int32(Date().timeIntervalSince1970), state: .uploading(0.0)))
break loop
}
case .backSide:
if let removeDocumentId = removeDocumentId {
innerState = removeDocumentWithId(innerState, id: removeDocumentId)
}
loop: for resource in resources {
let id = arc4random64()
innerState.backSideDocument = .local(SecureIdVerificationLocalDocument(id: id, resource: SecureIdLocalImageResource(localId: id, source: resource), timestamp: Int32(Date().timeIntervalSince1970), state: .uploading(0.0)))
break loop
}
case .translation:
var addIndex = innerState.translations.count
if let removeDocumentId = removeDocumentId {
for i in 0 ..< innerState.translations.count {
if innerState.translations[i].id == removeDocumentId {
innerState.translations.remove(at: i)
addIndex = i
break
}
}
}
for resource in resources {
let id = arc4random64()
innerState.translations.append(.local(SecureIdVerificationLocalDocument(id: id, resource: SecureIdLocalImageResource(localId: id, source: resource), timestamp: Int32(Date().timeIntervalSince1970), state: .uploading(0.0))))
innerState.translations.insert(.local(SecureIdVerificationLocalDocument(id: id, resource: SecureIdLocalImageResource(localId: id, source: resource), timestamp: Int32(Date().timeIntervalSince1970), state: .uploading(0.0))), at: addIndex)
addIndex += 1
}
if innerState.translations.count > 20 {
innerState.translations = Array(innerState.documents[0 ..< 20])
@ -2483,6 +2587,95 @@ final class SecureIdDocumentFormControllerNode: FormControllerNode<SecureIdDocum
self.present(controller, nil)
}
private func openDocument(document: SecureIdVerificationDocument) {
let controller = ActionSheetController(presentationTheme: theme)
let dismissAction: () -> Void = { [weak controller] in
controller?.dismissAnimated()
}
controller.setItemGroups([
ActionSheetItemGroup(items: [
ActionSheetButtonItem(title: strings.Passport_Identity_FilesView, action: { [weak self] in
dismissAction()
self?.presentGallery(document: document)
}),
ActionSheetButtonItem(title: strings.Passport_Identity_FilesUploadNew, action: { [weak self] in
dismissAction()
guard let strongSelf = self else {
return
}
guard let innerState = strongSelf.innerState else {
return
}
var target: AddFileTarget?
let id = document.id
if let selfieDocument = innerState.selfieDocument, selfieDocument.id == id {
target = .selfie
}
if let frontSideDocument = innerState.frontSideDocument, frontSideDocument.id == id {
switch innerState.documentState {
case let .identity(identity):
if let document = identity.document {
target = .frontSide(document.type)
}
case .address:
break
}
}
if let backSideDocument = innerState.backSideDocument, backSideDocument.id == id {
switch innerState.documentState {
case let .identity(identity):
if let document = identity.document {
target = .backSide(document.type)
}
case .address:
break
}
}
for i in 0 ..< innerState.documents.count {
if innerState.documents[i].id == id {
target = .scan
break
}
}
for i in 0 ..< innerState.translations.count {
if innerState.translations[i].id == id {
target = .translation
break
}
}
if let target = target {
strongSelf.view.endEditing(true)
strongSelf.presentAssetPicker(target, replaceDocumentId: document.id)
}
}),
ActionSheetButtonItem(title: strings.Common_Delete, action: { [weak self] in
dismissAction()
guard let strongSelf = self else {
return
}
guard var innerState = strongSelf.innerState else {
return
}
innerState = removeDocumentWithId(innerState, id: document.id)
strongSelf.updateInnerState(transition: .immediate, with: innerState)
})
]),
ActionSheetItemGroup(items: [ActionSheetButtonItem(title: self.strings.Common_Cancel, action: { dismissAction() })])
])
self.view.endEditing(true)
self.present(controller, nil)
}
private func presentGallery(document: SecureIdVerificationDocument) {
guard let innerState = self.innerState else {
return