diff --git a/TelegramUI.xcodeproj/project.pbxproj b/TelegramUI.xcodeproj/project.pbxproj index 6b449ff22d..0518d98ded 100644 --- a/TelegramUI.xcodeproj/project.pbxproj +++ b/TelegramUI.xcodeproj/project.pbxproj @@ -8,6 +8,7 @@ /* Begin PBXBuildFile section */ 091BEAB3214552D9003AEA30 /* Vision.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D02DADBE2138D76F00116225 /* Vision.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; + 092F368D2154AAEA001A9F49 /* SFCompactRounded-Semibold.otf in Resources */ = {isa = PBXBuildFile; fileRef = 092F368C2154AAE9001A9F49 /* SFCompactRounded-Semibold.otf */; }; 09310D2C213ED5FB0020033A /* anim_read.json in Resources */ = {isa = PBXBuildFile; fileRef = 09310D14213BC5DE0020033A /* anim_read.json */; }; 09310D2D213ED5FB0020033A /* anim_pin.json in Resources */ = {isa = PBXBuildFile; fileRef = 09310D15213BC5DE0020033A /* anim_pin.json */; }; 09310D2E213ED5FB0020033A /* anim_unmute.json in Resources */ = {isa = PBXBuildFile; fileRef = 09310D16213BC5DE0020033A /* anim_unmute.json */; }; @@ -1022,6 +1023,7 @@ /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 092F368C2154AAE9001A9F49 /* SFCompactRounded-Semibold.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "SFCompactRounded-Semibold.otf"; sourceTree = ""; }; 09310D14213BC5DE0020033A /* anim_read.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = anim_read.json; sourceTree = ""; }; 09310D15213BC5DE0020033A /* anim_pin.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = anim_pin.json; sourceTree = ""; }; 09310D16213BC5DE0020033A /* anim_unmute.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = anim_unmute.json; sourceTree = ""; }; @@ -2164,6 +2166,15 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 092F368B2154AAD6001A9F49 /* Fonts */ = { + isa = PBXGroup; + children = ( + 092F368C2154AAE9001A9F49 /* SFCompactRounded-Semibold.otf */, + ); + name = Fonts; + path = TelegramUI/Resources/Fonts; + sourceTree = ""; + }; 09310D13213BC5DE0020033A /* Animations */ = { isa = PBXGroup; children = ( @@ -2520,6 +2531,7 @@ isa = PBXGroup; children = ( 09310D13213BC5DE0020033A /* Animations */, + 092F368B2154AAD6001A9F49 /* Fonts */, D0C12A1B1F33964900B3F66D /* ChatWallpaperBuiltin0.jpg */, D0E9BA681F056F4C00F079A4 /* Stripe */, D0E9B9E91F00853C00F079A4 /* PhoneCountries.txt */, @@ -4637,6 +4649,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 092F368D2154AAEA001A9F49 /* SFCompactRounded-Semibold.otf in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/TelegramUI/CallListCallItem.swift b/TelegramUI/CallListCallItem.swift index 9d208c1dd5..228c141cb1 100644 --- a/TelegramUI/CallListCallItem.swift +++ b/TelegramUI/CallListCallItem.swift @@ -168,7 +168,7 @@ class CallListCallItem: ListViewItem { private let separatorHeight = 1.0 / UIScreen.main.scale -private let avatarFont: UIFont = UIFont(name: "ArialRoundedMTBold", size: 15.0)! +private let avatarFont: UIFont = UIFont(name: ".SFCompactRounded-Semibold", size: 16.0)! class CallListCallItemNode: ItemListRevealOptionsItemNode { private let backgroundNode: ASDisplayNode diff --git a/TelegramUI/ChatAvatarNavigationNode.swift b/TelegramUI/ChatAvatarNavigationNode.swift index 590722b8aa..7fd2516bbf 100644 --- a/TelegramUI/ChatAvatarNavigationNode.swift +++ b/TelegramUI/ChatAvatarNavigationNode.swift @@ -2,8 +2,8 @@ import Foundation import AsyncDisplayKit import Display -private let normalFont = UIFont(name: "ArialRoundedMTBold", size: 16.0)! -private let smallFont = UIFont(name: "ArialRoundedMTBold", size: 12.0)! +private let normalFont = UIFont(name: ".SFCompactRounded-Semibold", size: 16.0)! +private let smallFont = UIFont(name: ".SFCompactRounded-Semibold", size: 12.0)! final class ChatAvatarNavigationNode: ASDisplayNode { let avatarNode: AvatarNode diff --git a/TelegramUI/ChatListItem.swift b/TelegramUI/ChatListItem.swift index 0c7a22a3b7..8adb2d88f9 100644 --- a/TelegramUI/ChatListItem.swift +++ b/TelegramUI/ChatListItem.swift @@ -205,7 +205,7 @@ private func leftRevealOptions(strings: PresentationStrings, theme: Presentation private let separatorHeight = 1.0 / UIScreen.main.scale -private let avatarFont: UIFont = UIFont(name: "ArialRoundedMTBold", size: 26.0)! +private let avatarFont: UIFont = UIFont(name: ".SFCompactRounded-Semibold", size: 26.0)! class ChatListItemNode: ItemListRevealOptionsItemNode { var item: ChatListItem? diff --git a/TelegramUI/ChatListSearchContainerNode.swift b/TelegramUI/ChatListSearchContainerNode.swift index 2f9a227272..1cc7077688 100644 --- a/TelegramUI/ChatListSearchContainerNode.swift +++ b/TelegramUI/ChatListSearchContainerNode.swift @@ -146,7 +146,8 @@ private enum ChatListRecentEntry: Comparable, Identifiable { if let user = primaryPeer as? TelegramUser { if let _ = user.botInfo { status = .custom(strings.Bot_GenericBotStatus) - } else if user.id != account.peerId, let presence = peer.presence { + } else if user.id != account.peerId { + let presence = peer.presence ?? TelegramUserPresence(status: .none) status = .presence(presence, timeFormat) } else { status = .none diff --git a/TelegramUI/ChatMediaInputPeerSpecificItem.swift b/TelegramUI/ChatMediaInputPeerSpecificItem.swift index 7afaee4c2e..23ac0992d0 100644 --- a/TelegramUI/ChatMediaInputPeerSpecificItem.swift +++ b/TelegramUI/ChatMediaInputPeerSpecificItem.swift @@ -56,7 +56,7 @@ final class ChatMediaInputPeerSpecificItem: ListViewItem { } } -private let avatarFont: UIFont = UIFont(name: "ArialRoundedMTBold", size: 10.0)! +private let avatarFont: UIFont = UIFont(name: ".SFCompactRounded-Semibold", size: 10.0)! private let boundingSize = CGSize(width: 41.0, height: 41.0) private let boundingImageSize = CGSize(width: 28.0, height: 28.0) private let highlightSize = CGSize(width: 35.0, height: 35.0) diff --git a/TelegramUI/ChatMessageAvatarAccessoryItem.swift b/TelegramUI/ChatMessageAvatarAccessoryItem.swift index 481c5b7a49..64e758bb27 100644 --- a/TelegramUI/ChatMessageAvatarAccessoryItem.swift +++ b/TelegramUI/ChatMessageAvatarAccessoryItem.swift @@ -3,7 +3,7 @@ import Postbox import Display import TelegramCore -private let avatarFont: UIFont = UIFont(name: "ArialRoundedMTBold", size: 15.0)! +private let avatarFont: UIFont = UIFont(name: ".SFCompactRounded-Semibold", size: 16.0)! final class ChatMessageAvatarAccessoryItem: ListViewAccessoryItem { private let account: Account diff --git a/TelegramUI/ChatMessageContactBubbleContentNode.swift b/TelegramUI/ChatMessageContactBubbleContentNode.swift index 8d6ad3ce60..2e0ec83d76 100644 --- a/TelegramUI/ChatMessageContactBubbleContentNode.swift +++ b/TelegramUI/ChatMessageContactBubbleContentNode.swift @@ -5,7 +5,7 @@ import SwiftSignalKit import Postbox import TelegramCore -private let avatarFont: UIFont = UIFont(name: "ArialRoundedMTBold", size: 15.0)! +private let avatarFont: UIFont = UIFont(name: ".SFCompactRounded-Semibold", size: 16.0)! private let titleFont = Font.medium(14.0) private let textFont = Font.regular(14.0) diff --git a/TelegramUI/ChatMessageLiveLocationPositionNode.swift b/TelegramUI/ChatMessageLiveLocationPositionNode.swift index 5b2e9b320e..539223a7f0 100644 --- a/TelegramUI/ChatMessageLiveLocationPositionNode.swift +++ b/TelegramUI/ChatMessageLiveLocationPositionNode.swift @@ -3,7 +3,7 @@ import Display import TelegramCore import Postbox -private let avatarFont: UIFont = UIFont(name: "ArialRoundedMTBold", size: 24.0)! +private let avatarFont: UIFont = UIFont(name: ".SFCompactRounded-Semibold", size: 24.0)! private let avatarBackgroundImage = UIImage(bundleImageName: "Chat/Message/LocationPin")?.precomposed() private func addPulseAnimations(layer: CALayer) { diff --git a/TelegramUI/ChatMessageLiveLocationTimerNode.swift b/TelegramUI/ChatMessageLiveLocationTimerNode.swift index 890b99aa3c..d01368e3a3 100644 --- a/TelegramUI/ChatMessageLiveLocationTimerNode.swift +++ b/TelegramUI/ChatMessageLiveLocationTimerNode.swift @@ -2,7 +2,7 @@ import Foundation import AsyncDisplayKit import Display -private let textFont: UIFont = UIFont(name: "ArialRoundedMTBold", size: 13.0)! +private let textFont: UIFont = UIFont(name: ".SFCompactRounded-Semibold", size: 13.0)! private class ChatMessageLiveLocationTimerNodeParams: NSObject { let backgroundColor: UIColor diff --git a/TelegramUI/ChatMessageNotificationItem.swift b/TelegramUI/ChatMessageNotificationItem.swift index efb10dfc05..0b36f35eb4 100644 --- a/TelegramUI/ChatMessageNotificationItem.swift +++ b/TelegramUI/ChatMessageNotificationItem.swift @@ -45,7 +45,7 @@ public final class ChatMessageNotificationItem: NotificationItem { } } -private let avatarFont: UIFont = UIFont(name: "ArialRoundedMTBold", size: 24.0)! +private let avatarFont: UIFont = UIFont(name: ".SFCompactRounded-Semibold", size: 24.0)! final class ChatMessageNotificationItemNode: NotificationItemNode { private var item: ChatMessageNotificationItem? diff --git a/TelegramUI/ChatReportPeerTitlePanelNode.swift b/TelegramUI/ChatReportPeerTitlePanelNode.swift index 7d76540d2d..624b5343fc 100644 --- a/TelegramUI/ChatReportPeerTitlePanelNode.swift +++ b/TelegramUI/ChatReportPeerTitlePanelNode.swift @@ -62,7 +62,7 @@ final class ChatReportPeerTitlePanelNode: ChatTitleAccessoryPanelNode { let panelHeight: CGFloat = 40.0 - let contentRightInset: CGFloat = 18.0 + rightInset + let contentRightInset: CGFloat = 14.0 + rightInset let closeButtonSize = self.closeButton.measure(CGSize(width: 100.0, height: 100.0)) transition.updateFrame(node: self.closeButton, frame: CGRect(origin: CGPoint(x: width - contentRightInset - closeButtonSize.width, y: floorToScreenPixels((panelHeight - closeButtonSize.height) / 2.0)), size: closeButtonSize)) diff --git a/TelegramUI/CommandChatInputPanelItem.swift b/TelegramUI/CommandChatInputPanelItem.swift index 548b02b08b..a514728250 100644 --- a/TelegramUI/CommandChatInputPanelItem.swift +++ b/TelegramUI/CommandChatInputPanelItem.swift @@ -72,7 +72,7 @@ final class CommandChatInputPanelItem: ListViewItem { } } -private let avatarFont: UIFont = UIFont(name: "ArialRoundedMTBold", size: 16.0)! +private let avatarFont: UIFont = UIFont(name: ".SFCompactRounded-Semibold", size: 16.0)! private let textFont = Font.medium(14.0) private let descriptionFont = Font.regular(14.0) diff --git a/TelegramUI/ContactListNode.swift b/TelegramUI/ContactListNode.swift index 7699177e84..69c5e65e7e 100644 --- a/TelegramUI/ContactListNode.swift +++ b/TelegramUI/ContactListNode.swift @@ -151,10 +151,9 @@ private enum ContactListNodeEntry: Comparable, Identifiable { case let .peer(peer, isGlobal): if isGlobal, let _ = peer.addressName { status = .addressName("") - } else if let presence = presence { - status = .presence(presence, timeFormat) } else { - status = .none + let presence = presence ?? TelegramUserPresence(status: .none) + status = .presence(presence, timeFormat) } itemPeer = .peer(peer: peer, chatPeer: peer) case let .deviceContact(id, contact): diff --git a/TelegramUI/ContactsPeerItem.swift b/TelegramUI/ContactsPeerItem.swift index 2be4f13b56..d09e72aab1 100644 --- a/TelegramUI/ContactsPeerItem.swift +++ b/TelegramUI/ContactsPeerItem.swift @@ -270,7 +270,7 @@ class ContactsPeerItem: ListViewItem { private let separatorHeight = 1.0 / UIScreen.main.scale -private let avatarFont: UIFont = UIFont(name: "ArialRoundedMTBold", size: 15.0)! +private let avatarFont: UIFont = UIFont(name: ".SFCompactRounded-Semibold", size: 16.0)! class ContactsPeerItemNode: ItemListRevealOptionsItemNode { private let backgroundNode: ASDisplayNode diff --git a/TelegramUI/ItemListAvatarAndNameItem.swift b/TelegramUI/ItemListAvatarAndNameItem.swift index 44ca25b0c2..cb154f664c 100644 --- a/TelegramUI/ItemListAvatarAndNameItem.swift +++ b/TelegramUI/ItemListAvatarAndNameItem.swift @@ -240,7 +240,7 @@ class ItemListAvatarAndNameInfoItem: ListViewItem, ItemListItem { } } -private let avatarFont: UIFont = UIFont(name: "ArialRoundedMTBold", size: 28.0)! +private let avatarFont: UIFont = UIFont(name: ".SFCompactRounded-Semibold", size: 28.0)! private let nameFont = Font.medium(19.0) private let statusFont = Font.regular(15.0) @@ -410,7 +410,7 @@ class ItemListAvatarAndNameInfoItemNode: ListViewItemNode, ItemListItemNode, Ite } else if let _ = peer.botInfo { statusText = item.strings.Bot_GenericBotStatus statusColor = item.theme.list.itemSecondaryTextColor - } else if case .generic = item.mode { + } else if case .generic = item.mode, !(peer.id.namespace == Namespaces.Peer.CloudUser && peer.id.id == 777000) { let presence = (item.presence as? TelegramUserPresence) ?? TelegramUserPresence(status: .none) let timestamp = CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970 let (string, activity) = stringAndActivityForUserPresence(strings: item.strings, timeFormat: .regular, presence: presence, relativeTo: Int32(timestamp)) diff --git a/TelegramUI/ItemListPeerItem.swift b/TelegramUI/ItemListPeerItem.swift index c9e07f8fa8..a63d725c39 100644 --- a/TelegramUI/ItemListPeerItem.swift +++ b/TelegramUI/ItemListPeerItem.swift @@ -151,7 +151,7 @@ private let titleBoldFont = Font.medium(17.0) private let statusFont = Font.regular(14.0) private let labelFont = Font.regular(13.0) private let labelDisclosureFont = Font.regular(17.0) -private let avatarFont: UIFont = UIFont(name: "ArialRoundedMTBold", size: 17.0)! +private let avatarFont: UIFont = UIFont(name: ".SFCompactRounded-Semibold", size: 17.0)! class ItemListPeerItemNode: ItemListRevealOptionsItemNode { private let backgroundNode: ASDisplayNode diff --git a/TelegramUI/JoinLinkPreviewPeerContentNode.swift b/TelegramUI/JoinLinkPreviewPeerContentNode.swift index 9876d60901..1ebed53a80 100644 --- a/TelegramUI/JoinLinkPreviewPeerContentNode.swift +++ b/TelegramUI/JoinLinkPreviewPeerContentNode.swift @@ -4,7 +4,7 @@ import Display import Postbox import TelegramCore -private let avatarFont: UIFont = UIFont(name: "ArialRoundedMTBold", size: 26.0)! +private let avatarFont: UIFont = UIFont(name: ".SFCompactRounded-Semibold", size: 26.0)! private final class MoreNode: ASDisplayNode { private let avatarNode = AvatarNode(font: Font.regular(24.0)) diff --git a/TelegramUI/LocationBroadcastActionSheetItem.swift b/TelegramUI/LocationBroadcastActionSheetItem.swift index 9fc27dd0e1..e54a457c56 100644 --- a/TelegramUI/LocationBroadcastActionSheetItem.swift +++ b/TelegramUI/LocationBroadcastActionSheetItem.swift @@ -39,7 +39,7 @@ public class LocationBroadcastActionSheetItem: ActionSheetItem { } } -private let avatarFont: UIFont = UIFont(name: "ArialRoundedMTBold", size: 15.0)! +private let avatarFont: UIFont = UIFont(name: ".SFCompactRounded-Semibold", size: 15.0)! public class LocationBroadcastActionSheetItemNode: ActionSheetItemNode { private let theme: ActionSheetControllerTheme diff --git a/TelegramUI/MentionChatInputPanelItem.swift b/TelegramUI/MentionChatInputPanelItem.swift index 1a587a4649..682b5e3a74 100644 --- a/TelegramUI/MentionChatInputPanelItem.swift +++ b/TelegramUI/MentionChatInputPanelItem.swift @@ -74,7 +74,7 @@ final class MentionChatInputPanelItem: ListViewItem { } } -private let avatarFont: UIFont = UIFont(name: "ArialRoundedMTBold", size: 16.0)! +private let avatarFont: UIFont = UIFont(name: ".SFCompactRounded-Semibold", size: 16.0)! private let primaryFont = Font.medium(14.0) private let secondaryFont = Font.regular(14.0) diff --git a/TelegramUI/MultipleAvatarsNode.swift b/TelegramUI/MultipleAvatarsNode.swift index 3415773321..49ce2f247d 100644 --- a/TelegramUI/MultipleAvatarsNode.swift +++ b/TelegramUI/MultipleAvatarsNode.swift @@ -4,7 +4,7 @@ import AsyncDisplayKit import Postbox import TelegramCore -private let avatarFont: UIFont = UIFont(name: "ArialRoundedMTBold", size: 13.0)! +private let avatarFont: UIFont = UIFont(name: ".SFCompactRounded-Semibold", size: 13.0)! final class MultipleAvatarsNode: ASDisplayNode { private var nodes: [(Peer, AvatarNode)] = [] diff --git a/TelegramUI/ProxyListSettingsController.swift b/TelegramUI/ProxyListSettingsController.swift index 1967f5daf3..69d306d466 100644 --- a/TelegramUI/ProxyListSettingsController.swift +++ b/TelegramUI/ProxyListSettingsController.swift @@ -198,8 +198,8 @@ private enum ProxySettingsControllerEntry: ItemListNodeEntry { }) case let .serversHeader(theme, text): return ItemListSectionHeaderItem(theme: theme, text: text, sectionId: self.section) - case let .addServer(theme, text, editing): - return ProxySettingsActionItem(theme: theme, title: text, sectionId: self.section, editing: false, action: { + case let .addServer(theme, text, _): + return ProxySettingsActionItem(theme: theme, title: text, icon: .add, sectionId: self.section, editing: false, action: { arguments.addNewServer() }) case let .server(_, theme, strings, settings, active, status, editing, enabled): diff --git a/TelegramUI/ProxySettingsActionItem.swift b/TelegramUI/ProxySettingsActionItem.swift index 77bf5222b8..d2484dec94 100644 --- a/TelegramUI/ProxySettingsActionItem.swift +++ b/TelegramUI/ProxySettingsActionItem.swift @@ -3,16 +3,23 @@ import Display import AsyncDisplayKit import SwiftSignalKit +enum ProxySettingsActionIcon { + case none + case add +} + class ProxySettingsActionItem: ListViewItem, ItemListItem { let theme: PresentationTheme let title: String + let icon: ProxySettingsActionIcon let editing: Bool let sectionId: ItemListSectionId let action: () -> Void - init(theme: PresentationTheme, title: String, sectionId: ItemListSectionId, editing: Bool, action: @escaping () -> Void) { + init(theme: PresentationTheme, title: String, icon: ProxySettingsActionIcon = .none, sectionId: ItemListSectionId, editing: Bool, action: @escaping () -> Void) { self.theme = theme self.title = title + self.icon = icon self.editing = editing self.sectionId = sectionId self.action = action @@ -117,7 +124,7 @@ class ProxySettingsActionItemNode: ListViewItemNode { if currentItem?.theme !== item.theme { updatedTheme = item.theme } - let leftInset: CGFloat = 50.0 + params.leftInset + let leftInset: CGFloat = (item.icon != .none ? 50.0 : 16.0) + params.leftInset let editingOffset: CGFloat = (item.editing ? 38.0 : 0.0) @@ -131,7 +138,7 @@ class ProxySettingsActionItemNode: ListViewItemNode { let layout = ListViewItemNodeLayout(contentSize: contentSize, insets: insets) let layoutSize = layout.size - let icon = PresentationResourcesItemList.plusIconImage(item.theme) + let icon = item.icon == .add ? PresentationResourcesItemList.plusIconImage(item.theme) : nil return (layout, { [weak self] animated in if let strongSelf = self { diff --git a/TelegramUI/Resources/Fonts/SFCompactRounded-Semibold.otf b/TelegramUI/Resources/Fonts/SFCompactRounded-Semibold.otf new file mode 100644 index 0000000000..100e58bff7 Binary files /dev/null and b/TelegramUI/Resources/Fonts/SFCompactRounded-Semibold.otf differ diff --git a/TelegramUI/SecureIdAuthControllerNode.swift b/TelegramUI/SecureIdAuthControllerNode.swift index 06503c26bd..854cc37db5 100644 --- a/TelegramUI/SecureIdAuthControllerNode.swift +++ b/TelegramUI/SecureIdAuthControllerNode.swift @@ -425,6 +425,15 @@ final class SecureIdAuthControllerNode: ViewControllerTracingNode { } } + let hasErrors: (SecureIdValueWithContext, SecureIdValueKey) -> Bool = { value, key in + for error in value.errors { + if case let .value(valueKey) = error.key, valueKey != key { + return value.errors.count > 1 + } + } + return !value.errors.isEmpty + } + switch field { case let .identity(personalDetails, document, selfie, translations): if let document = document { @@ -446,23 +455,34 @@ final class SecureIdAuthControllerNode: ViewControllerTracingNode { } } case let .oneOf(types): + var chosenByError = false outer: for type in types { if let value = findValue(formData.values, key: type.valueKey)?.1 { - switch value.value { - case .passport: - hasValueType = .passport - break outer - case .idCard: - hasValueType = .idCard - break outer - case .driversLicense: - hasValueType = .driversLicense - break outer - case .internalPassport: - hasValueType = .internalPassport - break outer - default: - break + let hasErrors = hasErrors(value, type.valueKey) + + let data = extractSecureIdValueAdditionalData(value.value) + var dataFilled = true + if selfie && !data.selfie { + dataFilled = false + } + if translations && !data.translation { + dataFilled = false + } + + if hasValueType == nil || ((hasErrors || dataFilled) && !chosenByError) { + chosenByError = hasErrors + switch value.value { + case .passport: + hasValueType = .passport + case .idCard: + hasValueType = .idCard + case .driversLicense: + hasValueType = .driversLicense + case .internalPassport: + hasValueType = .internalPassport + default: + break + } } } } @@ -506,26 +526,38 @@ final class SecureIdAuthControllerNode: ViewControllerTracingNode { } } case let .oneOf(types): + var chosenByError = false outer: for type in types { if let value = findValue(formData.values, key: type.valueKey)?.1 { - switch value.value { - case .utilityBill: - hasValueType = .utilityBill - break outer - case .bankStatement: - hasValueType = .bankStatement - break outer - case .rentalAgreement: - hasValueType = .rentalAgreement - break outer - case .passportRegistration: - hasValueType = .passportRegistration - break outer - case .temporaryRegistration: - hasValueType = .temporaryRegistration - break outer - default: - break + let hasErrors = hasErrors(value, type.valueKey) + + let data = extractSecureIdValueAdditionalData(value.value) + var dataFilled = true + if translation && !data.translation { + dataFilled = false + } + + if hasValueType == nil || ((hasErrors || dataFilled) && !chosenByError) { + chosenByError = hasErrors + switch value.value { + case .utilityBill: + hasValueType = .utilityBill + break outer + case .bankStatement: + hasValueType = .bankStatement + break outer + case .rentalAgreement: + hasValueType = .rentalAgreement + break outer + case .passportRegistration: + hasValueType = .passportRegistration + break outer + case .temporaryRegistration: + hasValueType = .temporaryRegistration + break outer + default: + break + } } } } diff --git a/TelegramUI/SecureIdAuthFormFieldNode.swift b/TelegramUI/SecureIdAuthFormFieldNode.swift index ca222b1798..428441b687 100644 --- a/TelegramUI/SecureIdAuthFormFieldNode.swift +++ b/TelegramUI/SecureIdAuthFormFieldNode.swift @@ -204,6 +204,9 @@ private func findValuesForField(field: SecureIdParsedRequestedFormField, values: if personalDetails != nil { if let value = findValue(values, key: .personalDetails)?.1 { result.append(value) + if !value.errors.isEmpty { + filled = false + } } else { filled = false } @@ -213,13 +216,16 @@ private func findValuesForField(field: SecureIdParsedRequestedFormField, values: case let .just(type): if let value = findValue(values, key: type.valueKey)?.1 { result.append(value) - let data = extractValueAdditionalData(value.value) + let data = extractSecureIdValueAdditionalData(value.value) if selfie && !data.selfie { filled = false } if translation && !data.translation { filled = false } + if !value.errors.isEmpty { + filled = false + } } else { filled = false } @@ -231,7 +237,7 @@ private func findValuesForField(field: SecureIdParsedRequestedFormField, values: if bestMatchingValue == nil { bestMatchingValue = value } - let data = extractValueAdditionalData(value.value) + let data = extractSecureIdValueAdditionalData(value.value) var dataFilled = true if selfie && !data.selfie { dataFilled = false @@ -251,6 +257,9 @@ private func findValuesForField(field: SecureIdParsedRequestedFormField, values: } if let bestMatchingValue = bestMatchingValue { result.append(bestMatchingValue) + if !bestMatchingValue.errors.isEmpty { + filled = false + } } } } @@ -261,6 +270,9 @@ private func findValuesForField(field: SecureIdParsedRequestedFormField, values: if addressDetails { if let value = findValue(values, key: .address)?.1 { result.append(value) + if !value.errors.isEmpty { + filled = false + } } else { filled = false } @@ -270,10 +282,13 @@ private func findValuesForField(field: SecureIdParsedRequestedFormField, values: case let .just(type): if let value = findValue(values, key: type.valueKey)?.1 { result.append(value) - let data = extractValueAdditionalData(value.value) + let data = extractSecureIdValueAdditionalData(value.value) if translation && !data.translation { filled = false } + if !value.errors.isEmpty { + filled = false + } } else { filled = false } @@ -285,7 +300,7 @@ private func findValuesForField(field: SecureIdParsedRequestedFormField, values: if bestMatchingValue == nil { bestMatchingValue = value } - let data = extractValueAdditionalData(value.value) + let data = extractSecureIdValueAdditionalData(value.value) var dataFilled = true if translation && !data.translation { dataFilled = false @@ -302,6 +317,9 @@ private func findValuesForField(field: SecureIdParsedRequestedFormField, values: } if let bestMatchingValue = bestMatchingValue { result.append(bestMatchingValue) + if !bestMatchingValue.errors.isEmpty { + filled = false + } } } } @@ -673,43 +691,72 @@ private func fieldTitleAndText(field: SecureIdParsedRequestedFormField, strings: return (title, text.isEmpty ? placeholder : text) } -private struct ValueAdditionalData { - var nativeNames: Bool = false - var selfie: Bool = false - var translation: Bool = false -} - -private func extractValueAdditionalData(_ value: SecureIdValue) -> ValueAdditionalData { - var data = ValueAdditionalData() - switch value { - case let .personalDetails(value): - data.nativeNames = value.nativeName != nil - case let .passport(value): - data.selfie = value.selfieDocument != nil - data.translation = !value.translations.isEmpty - case let .internalPassport(value): - data.selfie = value.selfieDocument != nil - data.translation = !value.translations.isEmpty - case let .idCard(value): - data.selfie = value.selfieDocument != nil - data.translation = !value.translations.isEmpty - case let .driversLicense(value): - data.selfie = value.selfieDocument != nil - data.translation = !value.translations.isEmpty - case let .utilityBill(value): - data.translation = !value.translations.isEmpty - case let .rentalAgreement(value): - data.translation = !value.translations.isEmpty - case let .bankStatement(value): - data.translation = !value.translations.isEmpty - case let .temporaryRegistration(value): - data.translation = !value.translations.isEmpty - case let .passportRegistration(value): - data.translation = !value.translations.isEmpty +private func fieldErrorText(field: SecureIdParsedRequestedFormField, values: [SecureIdValueWithContext]) -> String? { + switch field { + case let .identity(personalDetails, document, _, _): + if let _ = personalDetails, let value = findValue(values, key: .personalDetails)?.1 { + if let error = value.errors[.value(.personalDetails)] { + return error + } else if let error = value.errors.first?.value { + return error + } + } + if let document = document { + switch document { + case let .just(type): + if let value = findValue(values, key: type.valueKey)?.1 { + if let error = value.errors[.value(type.valueKey)] { + return error + } else if let error = value.errors.first?.value { + return error + } + } + case let .oneOf(types): + for type in types { + if let value = findValue(values, key: type.valueKey)?.1 { + if let error = value.errors[.value(type.valueKey)] { + return error + } else if let error = value.errors.first?.value { + return error + } + } + } + } + } + case let .address(addressDetails, document, _): + if addressDetails, let value = findValue(values, key: .address)?.1 { + if let error = value.errors[.value(.address)] { + return error + } else if let error = value.errors.first?.value { + return error + } + } + if let document = document { + switch document { + case let .just(type): + if let value = findValue(values, key: type.valueKey)?.1 { + if let error = value.errors[.value(type.valueKey)] { + return error + } else if let error = value.errors.first?.value { + return error + } + } + case let .oneOf(types): + for type in types { + if let value = findValue(values, key: type.valueKey)?.1 { + if let error = value.errors[.value(type.valueKey)] { + return error + } else if let error = value.errors.first?.value { + return error + } + } + } + } + } default: - break + return nil } - return data + return nil } final class SecureIdAuthFormFieldNode: ASDisplayNode { @@ -805,116 +852,128 @@ final class SecureIdAuthFormFieldNode: ASDisplayNode { func updateValues(_ values: [SecureIdValueWithContext]) { var (title, text) = fieldTitleAndText(field: self.field, strings: self.strings, values: values) - let textColor = self.theme.list.itemSecondaryTextColor - /*switch self.field { - case .identity: - if let error = errors[.personalDetails]?.first { - text = error - textColor = self.theme.list.itemDestructiveColor - } - default: - break - }*/ - + var textColor = self.theme.list.itemSecondaryTextColor + var filled = true - switch self.field { - case let .identity(personalDetails, document, selfie, translation): - if let personalDetails = personalDetails { - if let value = findValue(values, key: .personalDetails)?.1 { - let data = extractValueAdditionalData(value.value) - if personalDetails.nativeNames && !data.nativeNames { + + if let errorText = fieldErrorText(field: self.field, values: values) { + filled = false + textColor = self.theme.list.itemDestructiveColor + text = errorText + } else { + switch self.field { + case let .identity(personalDetails, document, selfie, translation): + if let personalDetails = personalDetails { + if let value = findValue(values, key: .personalDetails)?.1 { + let data = extractSecureIdValueAdditionalData(value.value) + if personalDetails.nativeNames && !data.nativeNames { + filled = false + text = strings.Passport_FieldIdentityDetailsHelp + } + } else { filled = false text = strings.Passport_FieldIdentityDetailsHelp } - } else { - filled = false - text = strings.Passport_FieldIdentityDetailsHelp } - } - if let document = document { - switch document { - case let .just(type): - if let value = findValue(values, key: type.valueKey)?.1 { - let data = extractValueAdditionalData(value.value) - if selfie && !data.selfie { - filled = false - text = strings.Passport_FieldIdentitySelfieHelp - } - if translation && !data.translation { - filled = false - text = strings.Passport_FieldIdentityTranslationHelp - } - } else { - filled = false - } - case let .oneOf(types): - var anyDocument = false - for type in types { + if let document = document { + switch document { + case let .just(type): if let value = findValue(values, key: type.valueKey)?.1 { - let data = extractValueAdditionalData(value.value) - var dataFilled = true + let data = extractSecureIdValueAdditionalData(value.value) if selfie && !data.selfie { - dataFilled = false + filled = false + text = strings.Passport_FieldIdentitySelfieHelp } if translation && !data.translation { - dataFilled = false + filled = false + text = strings.Passport_FieldIdentityTranslationHelp } - if dataFilled { - anyDocument = true - } - } - } - if !anyDocument { - filled = false - } - } - } - case let .address(addressDetails, document, translation): - if addressDetails { - if findValue(values, key: .address) == nil { - filled = false - text = strings.Passport_FieldAddressHelp - } - } - if let document = document { - switch document { - case let .just(type): - if let value = findValue(values, key: type.valueKey)?.1 { - let data = extractValueAdditionalData(value.value) - if translation && !data.translation { + } else { filled = false - text = strings.Passport_FieldAddressTranslationHelp } - } else { - filled = false - } - case let .oneOf(types): - var anyDocument = false - for type in types { - if let value = findValue(values, key: type.valueKey)?.1 { - let data = extractValueAdditionalData(value.value) - var dataFilled = true - if translation && !data.translation { - dataFilled = false - } - if dataFilled { - anyDocument = true + case let .oneOf(types): + var anyDocument = false + var missingSelfie = false + var missingTranslation = false + for type in types { + if let value = findValue(values, key: type.valueKey)?.1 { + let data = extractSecureIdValueAdditionalData(value.value) + var dataFilled = true + if selfie && !data.selfie { + dataFilled = false + missingSelfie = true + } + if translation && !data.translation { + dataFilled = false + missingTranslation = true + } + if dataFilled { + anyDocument = true + } } } - } - if !anyDocument { - filled = false - } + if !anyDocument { + filled = false + if missingSelfie { + text = strings.Passport_FieldIdentitySelfieHelp + } else if missingTranslation { + text = strings.Passport_FieldIdentityTranslationHelp + } + } + } } - } - case .phone: - if findValue(values, key: .phone) == nil { - filled = false - } - case .email: - if findValue(values, key: .email) == nil { - filled = false - } + case let .address(addressDetails, document, translation): + if addressDetails { + if findValue(values, key: .address) == nil { + filled = false + text = strings.Passport_FieldAddressHelp + } + } + if let document = document { + switch document { + case let .just(type): + if let value = findValue(values, key: type.valueKey)?.1 { + let data = extractSecureIdValueAdditionalData(value.value) + if translation && !data.translation { + filled = false + text = strings.Passport_FieldAddressTranslationHelp + } + } else { + filled = false + } + case let .oneOf(types): + var anyDocument = false + var missingTranslation = false + for type in types { + if let value = findValue(values, key: type.valueKey)?.1 { + let data = extractSecureIdValueAdditionalData(value.value) + var dataFilled = true + if translation && !data.translation { + dataFilled = false + missingTranslation = true + } + if dataFilled { + anyDocument = true + } + } + } + if !anyDocument { + filled = false + if missingTranslation { + text = strings.Passport_FieldIdentityTranslationHelp + } + } + } + } + case .phone: + if findValue(values, key: .phone) == nil { + filled = false + } + case .email: + if findValue(values, key: .email) == nil { + filled = false + } + } } self.titleNode.attributedText = NSAttributedString(string: title, font: titleFont, textColor: self.theme.list.itemPrimaryTextColor) diff --git a/TelegramUI/SecureIdAuthHeaderNode.swift b/TelegramUI/SecureIdAuthHeaderNode.swift index da895ba5ab..eaab53760e 100644 --- a/TelegramUI/SecureIdAuthHeaderNode.swift +++ b/TelegramUI/SecureIdAuthHeaderNode.swift @@ -5,7 +5,7 @@ import Postbox import TelegramCore import SwiftSignalKit -private let avatarFont: UIFont = UIFont(name: "ArialRoundedMTBold", size: 26.0)! +private let avatarFont: UIFont = UIFont(name: ".SFCompactRounded-Semibold", size: 26.0)! private let titleFont: UIFont = Font.semibold(14.0) private let textFont: UIFont = Font.regular(14.0) diff --git a/TelegramUI/SecureIdDocumentFormController.swift b/TelegramUI/SecureIdDocumentFormController.swift index 008b3b80ae..b028a7f554 100644 --- a/TelegramUI/SecureIdDocumentFormController.swift +++ b/TelegramUI/SecureIdDocumentFormController.swift @@ -74,7 +74,7 @@ final class SecureIdDocumentFormController: FormController = [] + var badFileHashes: Set? + var badTranslationHashes: Set? + for value in self.previousValues { + for error in value.value.errors { + switch error.key { + case .value, .field: + return .saveNotAvailable + case let .file(hash), let .selfie(hash), let .frontSide(hash), let .backSide(hash), let .translationFile(hash): + badHashes.insert(hash) + case let .files(hashes): + badFileHashes = hashes + case let .translationFiles(hashes): + badTranslationHashes = hashes + } + } + } + var documentsRequired = false switch self.documentState { @@ -958,7 +976,7 @@ struct SecureIdDocumentFormState: FormControllerInnerState { } } - func isDocumentReady(_ document: SecureIdVerificationDocument?) -> Bool { + func isDocumentReady(_ document: SecureIdVerificationDocument?, badHashes: Set? = nil) -> Bool { if let document = document { switch document { case let .local(local): @@ -968,8 +986,12 @@ struct SecureIdDocumentFormState: FormControllerInnerState { case .uploaded: return true } - case .remote: - return true + case let .remote(reference): + if let badHashes = badHashes { + return !badHashes.contains(reference.fileHash) + } else { + return true + } } } else { return false @@ -977,40 +999,64 @@ struct SecureIdDocumentFormState: FormControllerInnerState { } if self.frontSideRequired { - guard isDocumentReady(self.frontSideDocument) else { + guard isDocumentReady(self.frontSideDocument, badHashes: badHashes) else { return .saveNotAvailable } } if self.backSideRequired { - guard isDocumentReady(self.backSideDocument) else { + guard isDocumentReady(self.backSideDocument, badHashes: badHashes) else { return .saveNotAvailable } } if self.selfieRequired { - guard isDocumentReady(self.selfieDocument) else { + guard isDocumentReady(self.selfieDocument, badHashes: badHashes) else { return .saveNotAvailable } } + var fileHashes: Set = [] for document in self.documents { guard isDocumentReady(document) else { return .saveNotAvailable } + switch document { + case let .remote(reference): + fileHashes.insert(reference.fileHash) + case let .local(document): + if case let .uploaded(file) = document.state { + fileHashes.insert(file.fileHash) + } + } } if documentsRequired && self.documents.isEmpty { return .saveNotAvailable } + if let badFileHashes = badFileHashes, badFileHashes == fileHashes { + return .saveNotAvailable + } + var translationHashes: Set = [] for document in self.translations { guard isDocumentReady(document) else { return .saveNotAvailable } + switch document { + case let .remote(reference): + translationHashes.insert(reference.fileHash) + case let .local(document): + if case let .uploaded(file) = document.state { + translationHashes.insert(file.fileHash) + } + } } if self.translationsRequired && self.translations.isEmpty { return .saveNotAvailable } + if let badTranslationHashes = badTranslationHashes, badTranslationHashes == translationHashes { + return .saveNotAvailable + } return .saveAvailable } @@ -2145,8 +2191,9 @@ final class SecureIdDocumentFormControllerNode: FormControllerNode ViewControll }) } shareMyContactImpl = { [weak controller] in - let _ = (peerView.get() - |> take(1) - |> deliverOnMainQueue).start(next: { view in - guard let peer = peerViewMainPeer(view) as? TelegramUser, let phone = peer.phone else { + let _ = (getUserPeer(postbox: account.postbox, peerId: account.peerId) + |> deliverOnMainQueue).start(next: { peer in + guard let peer = peer as? TelegramUser, let phone = peer.phone else { return } - let contact = TelegramMediaContact(firstName: peer.firstName ?? "", lastName: peer.lastName ?? "", phoneNumber: phone, peerId: peer.id, vCardData: nil) let _ = (enqueueMessages(account: account, peerId: peerId, messages: [.message(text: "", attributes: [], mediaReference: .standalone(media: contact), replyToMessageId: nil, localGroupingKey: nil)])