diff --git a/Images.xcassets/Item List/SearchIcon.imageset/Contents.json b/Images.xcassets/Item List/SearchIcon.imageset/Contents.json new file mode 100644 index 0000000000..d0860847fb --- /dev/null +++ b/Images.xcassets/Item List/SearchIcon.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "ic_search@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "ic_search@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Images.xcassets/Item List/SearchIcon.imageset/ic_search@2x.png b/Images.xcassets/Item List/SearchIcon.imageset/ic_search@2x.png new file mode 100644 index 0000000000..8c3c79e804 Binary files /dev/null and b/Images.xcassets/Item List/SearchIcon.imageset/ic_search@2x.png differ diff --git a/Images.xcassets/Item List/SearchIcon.imageset/ic_search@3x.png b/Images.xcassets/Item List/SearchIcon.imageset/ic_search@3x.png new file mode 100644 index 0000000000..51b2f82727 Binary files /dev/null and b/Images.xcassets/Item List/SearchIcon.imageset/ic_search@3x.png differ diff --git a/TelegramUI.xcodeproj/project.pbxproj b/TelegramUI.xcodeproj/project.pbxproj index eb87106474..d2d73739bb 100644 --- a/TelegramUI.xcodeproj/project.pbxproj +++ b/TelegramUI.xcodeproj/project.pbxproj @@ -188,6 +188,8 @@ D056CD7C1FF3E92C00880D28 /* DirectionalPanGestureRecognizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = D056CD7B1FF3E92C00880D28 /* DirectionalPanGestureRecognizer.swift */; }; D0642EFC1F3E1E7B00792790 /* ChatHistoryNavigationButtons.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0642EFB1F3E1E7B00792790 /* ChatHistoryNavigationButtons.swift */; }; D064EF871F69A06F00AC0398 /* MessageContentKind.swift in Sources */ = {isa = PBXBuildFile; fileRef = D064EF861F69A06F00AC0398 /* MessageContentKind.swift */; }; + D0671F232143BDA6000A8AE7 /* TwoStepVerificationEmptyItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0671F222143BDA6000A8AE7 /* TwoStepVerificationEmptyItem.swift */; }; + D0671F2D2145AB28000A8AE7 /* LegacyAvatarPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0671F2C2145AB28000A8AE7 /* LegacyAvatarPicker.swift */; }; D067B4A5211C911C00796039 /* LegacyChannelIntroController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D067B4A4211C911C00796039 /* LegacyChannelIntroController.swift */; }; D067B4AA211C916300796039 /* TGChannelIntroController.h in Headers */ = {isa = PBXBuildFile; fileRef = D067B4A6211C916200796039 /* TGChannelIntroController.h */; }; D067B4AD211C916300796039 /* TGChannelIntroController.m in Sources */ = {isa = PBXBuildFile; fileRef = D067B4A9211C916200796039 /* TGChannelIntroController.m */; }; @@ -309,6 +311,7 @@ D0B37C5C1F8D22AE004252DF /* ThemeSettingsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B37C5B1F8D22AE004252DF /* ThemeSettingsController.swift */; }; D0B37C5E1F8D26A8004252DF /* ThemeSettingsChatPreviewItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B37C5D1F8D26A8004252DF /* ThemeSettingsChatPreviewItem.swift */; }; D0B37C601F8D286E004252DF /* ThemeSettingsFontSizeItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B37C5F1F8D286E004252DF /* ThemeSettingsFontSizeItem.swift */; }; + D0B3AC802142E2E900CD1374 /* ResetPasswordController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B3AC7F2142E2E900CD1374 /* ResetPasswordController.swift */; }; D0B4AF861EC111FA00D51FF6 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D0AB0BBA1D6719B5002C78E7 /* Images.xcassets */; }; D0B4AF881EC112EE00D51FF6 /* CallKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D0B4AF871EC112ED00D51FF6 /* CallKit.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; D0B4AF8B1EC1133600D51FF6 /* CallKitIntergation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B4AF8A1EC1133600D51FF6 /* CallKitIntergation.swift */; }; @@ -1437,6 +1440,8 @@ D0613FD41E6064D200202CDB /* ConvertToSupergroupController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConvertToSupergroupController.swift; sourceTree = ""; }; D0642EFB1F3E1E7B00792790 /* ChatHistoryNavigationButtons.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChatHistoryNavigationButtons.swift; sourceTree = ""; }; D064EF861F69A06F00AC0398 /* MessageContentKind.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageContentKind.swift; sourceTree = ""; }; + D0671F222143BDA6000A8AE7 /* TwoStepVerificationEmptyItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TwoStepVerificationEmptyItem.swift; sourceTree = ""; }; + D0671F2C2145AB28000A8AE7 /* LegacyAvatarPicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegacyAvatarPicker.swift; sourceTree = ""; }; D067B4A4211C911C00796039 /* LegacyChannelIntroController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegacyChannelIntroController.swift; sourceTree = ""; }; D067B4A6211C916200796039 /* TGChannelIntroController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TGChannelIntroController.h; sourceTree = ""; }; D067B4A9211C916200796039 /* TGChannelIntroController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TGChannelIntroController.m; sourceTree = ""; }; @@ -1626,6 +1631,7 @@ D0B37C5B1F8D22AE004252DF /* ThemeSettingsController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemeSettingsController.swift; sourceTree = ""; }; D0B37C5D1F8D26A8004252DF /* ThemeSettingsChatPreviewItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemeSettingsChatPreviewItem.swift; sourceTree = ""; }; D0B37C5F1F8D286E004252DF /* ThemeSettingsFontSizeItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemeSettingsFontSizeItem.swift; sourceTree = ""; }; + D0B3AC7F2142E2E900CD1374 /* ResetPasswordController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResetPasswordController.swift; sourceTree = ""; }; D0B417C21D7DE54E004562A4 /* ChatPresentationInterfaceState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChatPresentationInterfaceState.swift; sourceTree = ""; }; D0B4AF871EC112ED00D51FF6 /* CallKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CallKit.framework; path = System/Library/Frameworks/CallKit.framework; sourceTree = SDKROOT; }; D0B4AF8A1EC1133600D51FF6 /* CallKitIntergation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CallKitIntergation.swift; sourceTree = ""; }; @@ -2856,6 +2862,7 @@ D023ED2D1DDB5BEC00BD496D /* LegacyAttachmentMenu.swift */, D0119CCF20CAE75F00895300 /* LegacySecureIdAttachmentMenu.swift */, D023EBB11DDA800700BD496D /* LegacyMediaPickers.swift */, + D0671F2C2145AB28000A8AE7 /* LegacyAvatarPicker.swift */, D00E15251DDBD4E700ACF65C /* LegacyCamera.swift */, D023ED2F1DDB605D00BD496D /* LegacyEmptyController.swift */, D023ED311DDB60CF00BD496D /* LegacyNavigationController.swift */, @@ -4331,11 +4338,13 @@ D05A32EB1E6F1462002760B4 /* BlockedPeersController.swift */, D05B724C1E720393000BD3AD /* SelectivePrivacySettingsController.swift */, D0EF40DC1E72F00E000DFCD4 /* SelectivePrivacySettingsPeersController.swift */, + D0671F222143BDA6000A8AE7 /* TwoStepVerificationEmptyItem.swift */, D01C2AAA1E75E010001F6F9A /* TwoStepVerificationUnlockController.swift */, D0FA0ABE1E76E17F005BB9B7 /* TwoStepVerificationPasswordEntryController.swift */, D0FA0AC01E7725AA005BB9B7 /* TwoStepVerificationResetController.swift */, D0760B231E9D015D00F1F3C4 /* PasscodeOptionsController.swift */, D0CE6F6F213EEE5000BCD44B /* CreatePasswordController.swift */, + D0B3AC7F2142E2E900CD1374 /* ResetPasswordController.swift */, ); name = "Privacy and Security"; sourceTree = ""; @@ -4851,6 +4860,7 @@ D0461439200514F000EC0EF2 /* LiveLocationSummaryManager.swift in Sources */, D056CD781FF2A6EE00880D28 /* ChatMessageSwipeToReplyNode.swift in Sources */, D0CE67941F7DB45100FFB557 /* ChatMessageContactBubbleContentNode.swift in Sources */, + D0B3AC802142E2E900CD1374 /* ResetPasswordController.swift in Sources */, D0943AFE1FDAE454001522CC /* ChatMultipleAvatarsNavigationNode.swift in Sources */, D0ADF966212E05A300310BBC /* TonePlayer.swift in Sources */, D007019E2029EFDD006B9E34 /* ICloudResources.swift in Sources */, @@ -4956,6 +4966,7 @@ D0DE66061F9A51E200EF4AE9 /* GalleryHiddenMediaManager.swift in Sources */, D0EC6D5C1EB9F58800EBF1C3 /* ListMessageFileItemNode.swift in Sources */, D0471B561EFDB40F0074D609 /* BotCheckoutActionButton.swift in Sources */, + D0671F2D2145AB28000A8AE7 /* LegacyAvatarPicker.swift in Sources */, D0EC6D5D1EB9F58800EBF1C3 /* ListMessageSnippetItemNode.swift in Sources */, D0EC6D5E1EB9F58800EBF1C3 /* ListMessageHoleItem.swift in Sources */, D0EC6D5F1EB9F58800EBF1C3 /* GridMessageItem.swift in Sources */, @@ -5311,6 +5322,7 @@ D093D7E22062F40100BC3599 /* SecureIdDocumentFormControllerNode.swift in Sources */, D0B2F7702052B5A800D3BFB9 /* InviteContactsControllerNode.swift in Sources */, D0EC6E211EB9F58900EBF1C3 /* InstantPageController.swift in Sources */, + D0671F232143BDA6000A8AE7 /* TwoStepVerificationEmptyItem.swift in Sources */, D0EC6E221EB9F58900EBF1C3 /* InstantPageControllerNode.swift in Sources */, D0EC6E231EB9F58900EBF1C3 /* StickerPackPreviewController.swift in Sources */, 0941A9A4210B0E2E00EBE194 /* OpenInAppIconResources.swift in Sources */, diff --git a/TelegramUI/AuthorizationSequenceController.swift b/TelegramUI/AuthorizationSequenceController.swift index 5dbbbb5bfe..9c6c46e150 100644 --- a/TelegramUI/AuthorizationSequenceController.swift +++ b/TelegramUI/AuthorizationSequenceController.swift @@ -133,20 +133,33 @@ public final class AuthorizationSequenceController: NavigationController { controller.inProgress = false let text: String + var actions: [TextAlertAction] = [ + TextAlertAction(type: .defaultAction, title: strongSelf.strings.Common_OK, action: {}) + ] switch error { case .limitExceeded: text = strongSelf.strings.Login_CodeFloodError case .invalidPhoneNumber: text = strongSelf.strings.Login_InvalidPhoneError + actions.append(TextAlertAction(type: .defaultAction, title: strongSelf.strings.Login_PhoneNumberHelp, action: { + + })) case .phoneLimitExceeded: text = strongSelf.strings.Login_PhoneFloodError case .phoneBanned: text = strongSelf.strings.Login_PhoneBannedError case .generic: text = strongSelf.strings.Login_UnknownError + case .timeout: + text = strongSelf.strings.Login_NetworkError + actions.append(TextAlertAction(type: .genericAction, title: strongSelf.strings.ChatSettings_ConnectionType_UseProxy, action: { [weak controller] in + guard let strongSelf = self, let controller = controller else { + return + } + controller.present(proxySettingsController(postbox: strongSelf.account.postbox, network: strongSelf.account.network, mode: .modal, theme: defaultPresentationTheme, strings: strongSelf.strings, updatedPresentationData: .single((defaultPresentationTheme, strongSelf.strings))), in: .window(.root), with: ViewControllerPresentationArguments(presentationAnimation: .modalSheet)) + })) } - - controller.present(standardTextAlertController(theme: AlertControllerTheme(authTheme: strongSelf.theme), title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.strings.Common_OK, action: {})]), in: .window(.root)) + controller.present(standardTextAlertController(theme: AlertControllerTheme(authTheme: strongSelf.theme), title: nil, text: text, actions: actions), in: .window(.root)) } })) } @@ -218,29 +231,31 @@ public final class AuthorizationSequenceController: NavigationController { } else { controller?.inProgress = true strongSelf.actionDisposable.set((resendAuthorizationCode(account: strongSelf.account) - |> deliverOnMainQueue).start(next: { result in - controller?.inProgress = false - }, error: { error in - if let strongSelf = self, let controller = controller { - controller.inProgress = false - - let text: String - switch error { - case .limitExceeded: - text = strongSelf.strings.Login_CodeFloodError - case .invalidPhoneNumber: - text = strongSelf.strings.Login_InvalidPhoneError - case .phoneLimitExceeded: - text = strongSelf.strings.Login_PhoneFloodError - case .phoneBanned: - text = strongSelf.strings.Login_PhoneBannedError - case .generic: - text = strongSelf.strings.Login_UnknownError - } - - controller.present(standardTextAlertController(theme: AlertControllerTheme(authTheme: strongSelf.theme), title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.strings.Common_OK, action: {})]), in: .window(.root)) + |> deliverOnMainQueue).start(next: { result in + controller?.inProgress = false + }, error: { error in + if let strongSelf = self, let controller = controller { + controller.inProgress = false + + let text: String + switch error { + case .limitExceeded: + text = strongSelf.strings.Login_CodeFloodError + case .invalidPhoneNumber: + text = strongSelf.strings.Login_InvalidPhoneError + case .phoneLimitExceeded: + text = strongSelf.strings.Login_PhoneFloodError + case .phoneBanned: + text = strongSelf.strings.Login_PhoneBannedError + case .generic: + text = strongSelf.strings.Login_UnknownError + case .timeout: + text = strongSelf.strings.Login_NetworkError } - })) + + controller.present(standardTextAlertController(theme: AlertControllerTheme(authTheme: strongSelf.theme), title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.strings.Common_OK, action: {})]), in: .window(.root)) + } + })) } } } diff --git a/TelegramUI/AuthorizationSequenceSignUpController.swift b/TelegramUI/AuthorizationSequenceSignUpController.swift index 4c85b69bfe..c92eee5567 100644 --- a/TelegramUI/AuthorizationSequenceSignUpController.swift +++ b/TelegramUI/AuthorizationSequenceSignUpController.swift @@ -48,45 +48,15 @@ final class AuthorizationSequenceSignUpController: ViewController { } override public func loadDisplayNode() { - let currentAvatarMixin = Atomic(value: nil) + let currentAvatarMixin = Atomic(value: nil) self.displayNode = AuthorizationSequenceSignUpControllerNode(theme: self.theme, strings: self.strings, addPhoto: { [weak self] in - guard let strongSelf = self else { - return - } - let legacyController = LegacyController(presentation: .custom, theme: defaultPresentationTheme) - legacyController.statusBar.statusBarStyle = .Ignore - - let emptyController = LegacyEmptyController(context: legacyController.context)! - let navigationController = makeLegacyNavigationController(rootController: emptyController) - navigationController.setNavigationBarHidden(true, animated: false) - navigationController.navigationBar.transform = CGAffineTransform(translationX: -1000.0, y: 0.0) - - legacyController.bind(controller: navigationController) - - strongSelf.view.endEditing(true) - strongSelf.present(legacyController, in: .window(.root)) - - let mixin = TGMediaAvatarMenuMixin(context: legacyController.context, parentController: emptyController, hasDeleteButton: false, personalPhoto: true, saveEditedPhotos: false, saveCapturedMedia: false)! - let _ = currentAvatarMixin.swap(mixin) - mixin.didFinishWithImage = { image in - guard let strongSelf = self, let image = image else { - return - } - strongSelf.controllerNode.currentPhoto = image - } - /*mixin.didFinishWithDelete = { - }*/ - mixin.didDismiss = { [weak legacyController] in - let _ = currentAvatarMixin.swap(nil) - legacyController?.dismiss() - } - let menuController = mixin.present() - if let menuController = menuController { - menuController.customRemoveFromParentViewController = { [weak legacyController] in - legacyController?.dismiss() - } - } + presentLegacyAvatarPicker(holder: currentAvatarMixin, signup: true, theme: defaultPresentationTheme, present: { c, a in + self?.view.endEditing(true) + self?.present(c, in: .window(.root), with: a) + }, completion: { image in + self?.controllerNode.currentPhoto = image + }) }) self.displayNodeDidLoad() diff --git a/TelegramUI/AuthorizationSequenceSignUpControllerNode.swift b/TelegramUI/AuthorizationSequenceSignUpControllerNode.swift index 6dc3acdf57..f0b2e9669e 100644 --- a/TelegramUI/AuthorizationSequenceSignUpControllerNode.swift +++ b/TelegramUI/AuthorizationSequenceSignUpControllerNode.swift @@ -75,7 +75,7 @@ final class AuthorizationSequenceSignUpControllerNode: ASDisplayNode, UITextFiel self.currentOptionNode = ASTextNode() self.currentOptionNode.isLayerBacked = true self.currentOptionNode.displaysAsynchronously = false - self.currentOptionNode.attributedText = NSAttributedString(string: self.strings.Login_InfoHelp, font: Font.regular(16.0), textColor: theme.primaryColor, paragraphAlignment: .center) + self.currentOptionNode.attributedText = NSAttributedString(string: self.strings.Login_InfoHelp, font: Font.regular(16.0), textColor: theme.textPlaceholderColor, paragraphAlignment: .center) self.firstSeparatorNode = ASDisplayNode() self.firstSeparatorNode.isLayerBacked = true @@ -91,6 +91,11 @@ final class AuthorizationSequenceSignUpControllerNode: ASDisplayNode, UITextFiel self.firstNameField.textField.textAlignment = .natural self.firstNameField.textField.returnKeyType = .next self.firstNameField.textField.attributedPlaceholder = NSAttributedString(string: self.strings.UserInfo_FirstNamePlaceholder, font: self.firstNameField.textField.font, textColor: self.theme.textPlaceholderColor) + self.firstNameField.textField.autocapitalizationType = .words + self.firstNameField.textField.autocorrectionType = .no + if #available(iOSApplicationExtension 10.0, *) { + self.firstNameField.textField.textContentType = .givenName + } self.lastNameField = TextFieldNode() self.lastNameField.textField.font = Font.regular(20.0) @@ -98,6 +103,11 @@ final class AuthorizationSequenceSignUpControllerNode: ASDisplayNode, UITextFiel self.lastNameField.textField.textAlignment = .natural self.lastNameField.textField.returnKeyType = .done self.lastNameField.textField.attributedPlaceholder = NSAttributedString(string: strings.UserInfo_LastNamePlaceholder, font: self.lastNameField.textField.font, textColor: self.theme.textPlaceholderColor) + self.lastNameField.textField.autocapitalizationType = .words + self.lastNameField.textField.autocorrectionType = .no + if #available(iOSApplicationExtension 10.0, *) { + self.lastNameField.textField.textContentType = .familyName + } self.currentPhotoNode = ASImageNode() self.currentPhotoNode.isUserInteractionEnabled = false diff --git a/TelegramUI/ChannelAdminsController.swift b/TelegramUI/ChannelAdminsController.swift index 26c36ee619..df179f065f 100644 --- a/TelegramUI/ChannelAdminsController.swift +++ b/TelegramUI/ChannelAdminsController.swift @@ -562,8 +562,7 @@ public func channelAdminsController(account: Account, peerId: PeerId) -> ViewCon }, addAdmin: { updateState { current in - - presentControllerImpl?(ChannelMembersSearchController(account: account, peerId: peerId, mode: .promote, filters: [.exclude(current.temporaryAdmins.map({$0.peer.id}))], openPeer: { peer, participant in + presentControllerImpl?(ChannelMembersSearchController(account: account, peerId: peerId, mode: .promote, filters: [], openPeer: { peer, participant in let presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 } if peer.id == account.peerId { return @@ -684,6 +683,7 @@ public func channelAdminsController(account: Account, peerId: PeerId) -> ViewCon presentControllerImpl = { [weak controller] c, p in if let controller = controller { controller.present(c, in: .window(.root), with: p) + controller.view.endEditing(true) } } controller.visibleBottomContentOffsetChanged = { offset in diff --git a/TelegramUI/ChannelBlacklistController.swift b/TelegramUI/ChannelBlacklistController.swift index 0406126ffe..75f9c464a2 100644 --- a/TelegramUI/ChannelBlacklistController.swift +++ b/TelegramUI/ChannelBlacklistController.swift @@ -464,10 +464,15 @@ public func channelBlacklistController(account: Account, peerId: PeerId) -> View updateState { state in return state.withUpdatedSearchingMembers(false) } - }, openPeer: { _, participant in - if let participant = participant?.participant, case .member = participant { - presentControllerImpl?(channelBannedMemberController(account: account, peerId: peerId, memberId: participant.peerId, initialParticipant: participant, updated: { _ in - }), ViewControllerPresentationArguments(presentationAnimation: .modalSheet)) + }, openPeer: { _, rendered in + if let participant = rendered?.participant, case .member = participant, let channel = peerViewMainPeer(view) as? TelegramChannel { + if case .group = channel.info { + arguments.openPeer(participant) + // presentControllerImpl?(channelBannedMemberController(account: account, peerId: peerId, memberId: participant.peerId, initialParticipant: participant, updated: { _ in + // }), ViewControllerPresentationArguments(presentationAnimation: .modalSheet)) + } else if let rendered = rendered { + arguments.openPeerInfo(rendered.peer) + } } }) } @@ -484,6 +489,7 @@ public func channelBlacklistController(account: Account, peerId: PeerId) -> View presentControllerImpl = { [weak controller] c, p in if let controller = controller { controller.present(c, in: .window(.root), with: p) + controller.view.endEditing(true) } } diff --git a/TelegramUI/ChannelMembersSearchContainerNode.swift b/TelegramUI/ChannelMembersSearchContainerNode.swift index f043e536cf..a53343345d 100644 --- a/TelegramUI/ChannelMembersSearchContainerNode.swift +++ b/TelegramUI/ChannelMembersSearchContainerNode.swift @@ -87,10 +87,10 @@ private final class ChannelMembersSearchEntry: Comparable, Identifiable { return lhs.index < rhs.index } - func item(account: Account, theme: PresentationTheme, strings: PresentationStrings, peerSelected: @escaping (Peer, RenderedChannelParticipant?) -> Void) -> ListViewItem { + func item(account: Account, theme: PresentationTheme, strings: PresentationStrings, nameSortOrder: PresentationPersonNameOrder, nameDisplayOrder: PresentationPersonNameOrder, peerSelected: @escaping (Peer, RenderedChannelParticipant?) -> Void) -> ListViewItem { switch self.content { case let .peer(peer): - return ContactsPeerItem(theme: theme, strings: strings, account: account, peerMode: .peer, peer: .peer(peer: peer, chatPeer: peer), status: .none, enabled: true, selection: .none, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), index: nil, header: self.section.chatListHeaderType.flatMap({ ChatListSearchItemHeader(type: $0, theme: theme, strings: strings, actionTitle: nil, action: nil) }), action: { _ in + return ContactsPeerItem(theme: theme, strings: strings, sortOrder: nameSortOrder, displayOrder: nameDisplayOrder, account: account, peerMode: .peer, peer: .peer(peer: peer, chatPeer: peer), status: .none, enabled: true, selection: .none, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), index: nil, header: self.section.chatListHeaderType.flatMap({ ChatListSearchItemHeader(type: $0, theme: theme, strings: strings, actionTitle: nil, action: nil) }), action: { _ in peerSelected(peer, nil) }) case let .participant(participant, label, enabled): @@ -100,7 +100,7 @@ private final class ChannelMembersSearchEntry: Comparable, Identifiable { } else { status = .none } - return ContactsPeerItem(theme: theme, strings: strings, account: account, peerMode: .peer, peer: .peer(peer: participant.peer, chatPeer: participant.peer), status: status, enabled: enabled, selection: .none, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), index: nil, header: self.section.chatListHeaderType.flatMap({ ChatListSearchItemHeader(type: $0, theme: theme, strings: strings, actionTitle: nil, action: nil) }), action: { _ in + return ContactsPeerItem(theme: theme, strings: strings, sortOrder: nameSortOrder, displayOrder: nameDisplayOrder, account: account, peerMode: .peer, peer: .peer(peer: participant.peer, chatPeer: participant.peer), status: status, enabled: enabled, selection: .none, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), index: nil, header: self.section.chatListHeaderType.flatMap({ ChatListSearchItemHeader(type: $0, theme: theme, strings: strings, actionTitle: nil, action: nil) }), action: { _ in peerSelected(participant.peer, participant) }) } @@ -113,12 +113,12 @@ struct ChannelMembersSearchContainerTransition { let isSearching: Bool } -private func channelMembersSearchContainerPreparedRecentTransition(from fromEntries: [ChannelMembersSearchEntry], to toEntries: [ChannelMembersSearchEntry], isSearching: Bool, account: Account, theme: PresentationTheme, strings: PresentationStrings, peerSelected: @escaping (Peer, RenderedChannelParticipant?) -> Void) -> ChannelMembersSearchContainerTransition { +private func channelMembersSearchContainerPreparedRecentTransition(from fromEntries: [ChannelMembersSearchEntry], to toEntries: [ChannelMembersSearchEntry], isSearching: Bool, account: Account, theme: PresentationTheme, strings: PresentationStrings, nameSortOrder: PresentationPersonNameOrder, nameDisplayOrder: PresentationPersonNameOrder, peerSelected: @escaping (Peer, RenderedChannelParticipant?) -> Void) -> ChannelMembersSearchContainerTransition { let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromEntries, rightList: toEntries) let deletions = deleteIndices.map { ListViewDeleteItem(index: $0, directionHint: nil) } - let insertions = indicesAndItems.map { ListViewInsertItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(account: account, theme: theme, strings: strings, peerSelected: peerSelected), directionHint: nil) } - let updates = updateIndices.map { ListViewUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(account: account, theme: theme, strings: strings, peerSelected: peerSelected), directionHint: nil) } + let insertions = indicesAndItems.map { ListViewInsertItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(account: account, theme: theme, strings: strings, nameSortOrder: nameSortOrder, nameDisplayOrder: nameDisplayOrder, peerSelected: peerSelected), directionHint: nil) } + let updates = updateIndices.map { ListViewUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(account: account, theme: theme, strings: strings, nameSortOrder: nameSortOrder, nameDisplayOrder: nameDisplayOrder, peerSelected: peerSelected), directionHint: nil) } return ChannelMembersSearchContainerTransition(deletions: deletions, insertions: insertions, updates: updates, isSearching: isSearching) } @@ -140,15 +140,16 @@ final class ChannelMembersSearchContainerNode: SearchDisplayControllerContentNod private var presentationData: PresentationData private var presentationDataDisposable: Disposable? - private let themeAndStringsPromise: Promise<(PresentationTheme, PresentationStrings)> + private let themeAndStringsPromise: Promise<(PresentationTheme, PresentationStrings, PresentationPersonNameOrder, PresentationPersonNameOrder)> - init(account: Account, peerId: PeerId, mode: ChannelMembersSearchMode, filters: [ChannelMembersSearchFilter], openPeer: @escaping (Peer, RenderedChannelParticipant?) -> Void) { + + init(account: Account, peerId: PeerId, mode: ChannelMembersSearchMode, filters: [ChannelMembersSearchFilter], openPeer: @escaping (Peer, RenderedChannelParticipant?) -> Void, updateActivity: @escaping(Bool)->Void) { self.account = account self.openPeer = openPeer self.mode = mode self.presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 } - self.themeAndStringsPromise = Promise((self.presentationData.theme, self.presentationData.strings)) + self.themeAndStringsPromise = Promise((self.presentationData.theme, self.presentationData.strings, self.presentationData.nameSortOrder, self.presentationData.nameDisplayOrder)) self.dimNode = ASDisplayNode() self.dimNode.backgroundColor = UIColor.black.withAlphaComponent(0.5) @@ -163,9 +164,12 @@ final class ChannelMembersSearchContainerNode: SearchDisplayControllerContentNod self.addSubnode(self.dimNode) self.addSubnode(self.listNode) + + let themeAndStringsPromise = self.themeAndStringsPromise let foundItems = searchQuery.get() |> mapToSignal { query -> Signal<[ChannelMembersSearchEntry]?, NoError> in + updateActivity(true) if let query = query, !query.isEmpty { let foundGroupMembers: Signal<[RenderedChannelParticipant], NoError> let foundMembers: Signal<[RenderedChannelParticipant], NoError> @@ -357,9 +361,9 @@ final class ChannelMembersSearchContainerNode: SearchDisplayControllerContentNod |> deliverOnMainQueue).start(next: { [weak self] entries, themeAndStrings in if let strongSelf = self { let previousEntries = previousSearchItems.swap(entries) - + updateActivity(false) let firstTime = previousEntries == nil - let transition = channelMembersSearchContainerPreparedRecentTransition(from: previousEntries ?? [], to: entries ?? [], isSearching: entries != nil, account: account, theme: themeAndStrings.0, strings: themeAndStrings.1, peerSelected: openPeer) + let transition = channelMembersSearchContainerPreparedRecentTransition(from: previousEntries ?? [], to: entries ?? [], isSearching: entries != nil, account: account, theme: themeAndStrings.0, strings: themeAndStrings.1, nameSortOrder: themeAndStrings.2, nameDisplayOrder: themeAndStrings.3, peerSelected: openPeer) strongSelf.enqueueTransition(transition, firstTime: firstTime) } })) diff --git a/TelegramUI/ChannelMembersSearchController.swift b/TelegramUI/ChannelMembersSearchController.swift index 12a5e32346..d7e4cde8f7 100644 --- a/TelegramUI/ChannelMembersSearchController.swift +++ b/TelegramUI/ChannelMembersSearchController.swift @@ -58,7 +58,7 @@ final class ChannelMembersSearchController: ViewController { } override func loadDisplayNode() { - self.displayNode = ChannelMembersSearchControllerNode(account: self.account, theme: self.presentationData.theme, strings: self.presentationData.strings, peerId: self.peerId, mode: self.mode, filters: self.filters) + self.displayNode = ChannelMembersSearchControllerNode(account: self.account, theme: self.presentationData.theme, strings: self.presentationData.strings, nameSortOrder: self.presentationData.nameSortOrder, nameDisplayOrder: self.presentationData.nameDisplayOrder, peerId: self.peerId, mode: self.mode, filters: self.filters) self.controllerNode.navigationBar = self.navigationBar self.controllerNode.requestActivateSearch = { [weak self] in self?.activateSearch() diff --git a/TelegramUI/ChannelMembersSearchControllerNode.swift b/TelegramUI/ChannelMembersSearchControllerNode.swift index 8a5a8c66c6..0a443a797c 100644 --- a/TelegramUI/ChannelMembersSearchControllerNode.swift +++ b/TelegramUI/ChannelMembersSearchControllerNode.swift @@ -67,7 +67,7 @@ private enum ChannelMembersSearchEntry: Comparable, Identifiable { } } - func item(account: Account, theme: PresentationTheme, strings: PresentationStrings, interaction: ChannelMembersSearchInteraction) -> ListViewItem { + func item(account: Account, theme: PresentationTheme, strings: PresentationStrings, nameSortOrder: PresentationPersonNameOrder, nameDisplayOrder: PresentationPersonNameOrder, interaction: ChannelMembersSearchInteraction) -> ListViewItem { switch self { case .search: return ChatListSearchItem(theme: theme, placeholder: strings.Common_Search, activate: { @@ -80,7 +80,7 @@ private enum ChannelMembersSearchEntry: Comparable, Identifiable { } else { status = .none } - return ContactsPeerItem(theme: theme, strings: strings, account: account, peerMode: .peer, peer: .peer(peer: participant.peer, chatPeer: nil), status: status, enabled: enabled, selection: .none, editing: editing, index: nil, header: nil, action: { _ in + return ContactsPeerItem(theme: theme, strings: strings, sortOrder: nameSortOrder, displayOrder: nameDisplayOrder, account: account, peerMode: .peer, peer: .peer(peer: participant.peer, chatPeer: nil), status: status, enabled: enabled, selection: .none, editing: editing, index: nil, header: nil, action: { _ in interaction.openPeer(participant.peer, participant) }) } @@ -94,12 +94,12 @@ private struct ChannelMembersSearchTransition { let initial: Bool } -private func preparedTransition(from fromEntries: [ChannelMembersSearchEntry]?, to toEntries: [ChannelMembersSearchEntry], account: Account, theme: PresentationTheme, strings: PresentationStrings, interaction: ChannelMembersSearchInteraction) -> ChannelMembersSearchTransition { +private func preparedTransition(from fromEntries: [ChannelMembersSearchEntry]?, to toEntries: [ChannelMembersSearchEntry], account: Account, theme: PresentationTheme, strings: PresentationStrings, nameSortOrder: PresentationPersonNameOrder, nameDisplayOrder: PresentationPersonNameOrder, interaction: ChannelMembersSearchInteraction) -> ChannelMembersSearchTransition { let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromEntries ?? [], rightList: toEntries) let deletions = deleteIndices.map { ListViewDeleteItem(index: $0, directionHint: nil) } - let insertions = indicesAndItems.map { ListViewInsertItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(account: account, theme: theme, strings: strings, interaction: interaction), directionHint: nil) } - let updates = updateIndices.map { ListViewUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(account: account, theme: theme, strings: strings, interaction: interaction), directionHint: nil) } + let insertions = indicesAndItems.map { ListViewInsertItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(account: account, theme: theme, strings: strings, nameSortOrder: nameSortOrder, nameDisplayOrder: nameDisplayOrder, interaction: interaction), directionHint: nil) } + let updates = updateIndices.map { ListViewUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(account: account, theme: theme, strings: strings, nameSortOrder: nameSortOrder, nameDisplayOrder: nameDisplayOrder, interaction: interaction), directionHint: nil) } return ChannelMembersSearchTransition(deletions: deletions, insertions: insertions, updates: updates, initial: fromEntries == nil) } @@ -127,7 +127,7 @@ class ChannelMembersSearchControllerNode: ASDisplayNode { private var disposable: Disposable? private var listControl: PeerChannelMemberCategoryControl? - init(account: Account, theme: PresentationTheme, strings: PresentationStrings, peerId: PeerId, mode: ChannelMembersSearchControllerMode, filters: [ChannelMembersSearchFilter]) { + init(account: Account, theme: PresentationTheme, strings: PresentationStrings, nameSortOrder: PresentationPersonNameOrder, nameDisplayOrder: PresentationPersonNameOrder, peerId: PeerId, mode: ChannelMembersSearchControllerMode, filters: [ChannelMembersSearchFilter]) { self.account = account self.listNode = ListView() self.peerId = peerId @@ -203,7 +203,7 @@ class ChannelMembersSearchControllerNode: ASDisplayNode { let previous = previousEntries.swap(entries) - strongSelf.enqueueTransition(preparedTransition(from: previous, to: entries, account: account, theme: theme, strings: strings, interaction: interaction)) + strongSelf.enqueueTransition(preparedTransition(from: previous, to: entries, account: account, theme: theme, strings: strings, nameSortOrder: nameSortOrder, nameDisplayOrder: nameDisplayOrder, interaction: interaction)) }) self.disposable = disposable self.listControl = loadMoreControl @@ -290,6 +290,8 @@ class ChannelMembersSearchControllerNode: ASDisplayNode { if let placeholderNode = maybePlaceholderNode { self.searchDisplayController = SearchDisplayController(theme: self.themeAndStrings.0, strings: self.themeAndStrings.1, contentNode: ChannelMembersSearchContainerNode(account: self.account, peerId: self.peerId, mode: .banAndPromoteActions, filters: self.filters, openPeer: { [weak self] peer, participant in self?.requestOpenPeerFromSearch?(peer, participant) + }, updateActivity: { value in + }), cancel: { [weak self] in if let requestDeactivateSearch = self?.requestDeactivateSearch { requestDeactivateSearch() diff --git a/TelegramUI/ChatListController.swift b/TelegramUI/ChatListController.swift index 9199f8986b..10e6dae9b0 100644 --- a/TelegramUI/ChatListController.swift +++ b/TelegramUI/ChatListController.swift @@ -253,12 +253,12 @@ public class ChatListController: TelegramController, UIViewControllerPreviewingD self.navigationBar?.updatePresentationData(NavigationBarPresentationData(presentationData: self.presentationData)) if self.isNodeLoaded { - self.chatListDisplayNode.updateThemeAndStrings(theme: self.presentationData.theme, strings: self.presentationData.strings, timeFormat: self.presentationData.timeFormat) + self.chatListDisplayNode.updateThemeAndStrings(theme: self.presentationData.theme, strings: self.presentationData.strings, timeFormat: self.presentationData.timeFormat, nameSortOrder: self.presentationData.nameSortOrder, nameDisplayOrder: self.presentationData.nameDisplayOrder) } } override public func loadDisplayNode() { - self.displayNode = ChatListControllerNode(account: self.account, groupId: self.groupId, controlsHistoryPreload: self.controlsHistoryPreload, theme: self.presentationData.theme, strings: self.presentationData.strings, timeFormat: self.presentationData.timeFormat) + self.displayNode = ChatListControllerNode(account: self.account, groupId: self.groupId, controlsHistoryPreload: self.controlsHistoryPreload, theme: self.presentationData.theme, strings: self.presentationData.strings, timeFormat: self.presentationData.timeFormat, nameSortOrder: self.presentationData.nameSortOrder, nameDisplayOrder: self.presentationData.nameDisplayOrder) self.chatListDisplayNode.navigationBar = self.navigationBar diff --git a/TelegramUI/ChatListControllerNode.swift b/TelegramUI/ChatListControllerNode.swift index c9a85b538a..a185a9d504 100644 --- a/TelegramUI/ChatListControllerNode.swift +++ b/TelegramUI/ChatListControllerNode.swift @@ -23,10 +23,10 @@ class ChatListControllerNode: ASDisplayNode { var themeAndStrings: (PresentationTheme, PresentationStrings, timeFormat: PresentationTimeFormat) - init(account: Account, groupId: PeerGroupId?, controlsHistoryPreload: Bool, theme: PresentationTheme, strings: PresentationStrings, timeFormat: PresentationTimeFormat) { + init(account: Account, groupId: PeerGroupId?, controlsHistoryPreload: Bool, theme: PresentationTheme, strings: PresentationStrings, timeFormat: PresentationTimeFormat, nameSortOrder: PresentationPersonNameOrder, nameDisplayOrder: PresentationPersonNameOrder) { self.account = account self.groupId = groupId - self.chatListNode = ChatListNode(account: account, groupId: groupId, controlsHistoryPreload: controlsHistoryPreload, mode: .chatList, theme: theme, strings: strings, timeFormat: timeFormat) + self.chatListNode = ChatListNode(account: account, groupId: groupId, controlsHistoryPreload: controlsHistoryPreload, mode: .chatList, theme: theme, strings: strings, timeFormat: timeFormat, nameSortOrder: nameSortOrder, nameDisplayOrder: nameDisplayOrder) self.themeAndStrings = (theme, strings, timeFormat) @@ -61,11 +61,11 @@ class ChatListControllerNode: ASDisplayNode { } } - func updateThemeAndStrings(theme: PresentationTheme, strings: PresentationStrings, timeFormat: PresentationTimeFormat) { + func updateThemeAndStrings(theme: PresentationTheme, strings: PresentationStrings, timeFormat: PresentationTimeFormat, nameSortOrder: PresentationPersonNameOrder, nameDisplayOrder: PresentationPersonNameOrder) { self.themeAndStrings = (theme, strings, timeFormat) self.backgroundColor = theme.chatList.backgroundColor - self.chatListNode.updateThemeAndStrings(theme: theme, strings: strings, timeFormat: timeFormat) + self.chatListNode.updateThemeAndStrings(theme: theme, strings: strings, timeFormat: timeFormat, nameSortOrder: nameSortOrder, nameDisplayOrder: nameDisplayOrder) self.searchDisplayController?.updateThemeAndStrings(theme: theme, strings: strings) self.chatListEmptyNode?.updateThemeAndStrings(theme: theme, strings: strings) } diff --git a/TelegramUI/ChatListEmptyNode.swift b/TelegramUI/ChatListEmptyNode.swift index 361da7fdd9..68ce3086ca 100644 --- a/TelegramUI/ChatListEmptyNode.swift +++ b/TelegramUI/ChatListEmptyNode.swift @@ -36,7 +36,7 @@ final class ChatListEmptyNode: ASDisplayNode { func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) { self.validLayout = size - let textSize = self.textNode.updateLayout(size) + let textSize = self.textNode.updateLayout(CGSize(width: size.width - 40.0, height: size.height)) transition.updateFrame(node: self.textNode, frame: CGRect(origin: CGPoint(x: floor((size.width - textSize.width) / 2.0), y: floor((size.height - textSize.height) / 2.0)), size: textSize)) } } diff --git a/TelegramUI/ChatListItem.swift b/TelegramUI/ChatListItem.swift index 5b61823a27..b7636df3b2 100644 --- a/TelegramUI/ChatListItem.swift +++ b/TelegramUI/ChatListItem.swift @@ -709,7 +709,11 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { if item.enableContextActions && !isAd { peerRevealOptions = revealOptions(strings: item.presentationData.strings, theme: item.presentationData.theme, isPinned: isPinned, isMuted: item.account.peerId != item.index.messageIndex.id.peerId ? (currentMutedIconImage != nil) : nil, hasPeerGroupId: hasPeerGroupId, canDelete: true) - peerLeftRevealOptions = leftRevealOptions(strings: item.presentationData.strings, theme: item.presentationData.theme, isUnread: unreadCount.unread) + if itemPeer.peerId != item.account.peerId { + peerLeftRevealOptions = leftRevealOptions(strings: item.presentationData.strings, theme: item.presentationData.theme, isUnread: unreadCount.unread) + } else { + peerLeftRevealOptions = [] + } } else { peerRevealOptions = [] peerLeftRevealOptions = [] diff --git a/TelegramUI/ChatListNode.swift b/TelegramUI/ChatListNode.swift index 9e2b0616ff..e31929c284 100644 --- a/TelegramUI/ChatListNode.swift +++ b/TelegramUI/ChatListNode.swift @@ -168,7 +168,7 @@ private func mappedInsertEntries(account: Account, nodeInteraction: ChatListNode enabled = false } } - return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ContactsPeerItem(theme: presentationData.theme, strings: presentationData.strings, account: account, peerMode: .generalSearch, peer: .peer(peer: itemPeer, chatPeer: chatPeer), status: .none, enabled: enabled, selection: .none, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), index: nil, header: nil, action: { _ in + return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ContactsPeerItem(theme: presentationData.theme, strings: presentationData.strings, sortOrder: presentationData.nameSortOrder, displayOrder: presentationData.nameDisplayOrder, account: account, peerMode: .generalSearch, peer: .peer(peer: itemPeer, chatPeer: chatPeer), status: .none, enabled: enabled, selection: .none, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), index: nil, header: nil, action: { _ in if let chatPeer = chatPeer { nodeInteraction.peerSelected(chatPeer) } @@ -229,7 +229,7 @@ private func mappedUpdateEntries(account: Account, nodeInteraction: ChatListNode enabled = false } } - return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ContactsPeerItem(theme: presentationData.theme, strings: presentationData.strings, account: account, peerMode: .generalSearch, peer: .peer(peer: itemPeer, chatPeer: chatPeer), status: .none, enabled: enabled, selection: .none, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), index: nil, header: nil, action: { _ in + return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ContactsPeerItem(theme: presentationData.theme, strings: presentationData.strings, sortOrder: presentationData.nameSortOrder, displayOrder: presentationData.nameDisplayOrder, account: account, peerMode: .generalSearch, peer: .peer(peer: itemPeer, chatPeer: chatPeer), status: .none, enabled: enabled, selection: .none, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), index: nil, header: nil, action: { _ in if let chatPeer = chatPeer { nodeInteraction.peerSelected(chatPeer) } @@ -333,12 +333,12 @@ final class ChatListNode: ListView { var isEmptyUpdated: ((Bool) -> Void)? private var wasEmpty: Bool? - init(account: Account, groupId: PeerGroupId?, controlsHistoryPreload: Bool, mode: ChatListNodeMode, theme: PresentationTheme, strings: PresentationStrings, timeFormat: PresentationTimeFormat) { + init(account: Account, groupId: PeerGroupId?, controlsHistoryPreload: Bool, mode: ChatListNodeMode, theme: PresentationTheme, strings: PresentationStrings, timeFormat: PresentationTimeFormat, nameSortOrder: PresentationPersonNameOrder, nameDisplayOrder: PresentationPersonNameOrder) { self.account = account self.controlsHistoryPreload = controlsHistoryPreload self.mode = mode - self.currentState = ChatListNodeState(presentationData: ChatListPresentationData(theme: theme, strings: strings, timeFormat: timeFormat), editing: false, peerIdWithRevealedOptions: nil, peerInputActivities: nil) + self.currentState = ChatListNodeState(presentationData: ChatListPresentationData(theme: theme, strings: strings, timeFormat: timeFormat, nameSortOrder: nameSortOrder, nameDisplayOrder: nameDisplayOrder), editing: false, peerIdWithRevealedOptions: nil, peerInputActivities: nil) self.statePromise = ValuePromise(self.currentState, ignoreRepeated: true) self.theme = theme @@ -766,7 +766,7 @@ final class ChatListNode: ListView { self.activityStatusesDisposable?.dispose() } - func updateThemeAndStrings(theme: PresentationTheme, strings: PresentationStrings, timeFormat: PresentationTimeFormat) { + func updateThemeAndStrings(theme: PresentationTheme, strings: PresentationStrings, timeFormat: PresentationTimeFormat, nameSortOrder: PresentationPersonNameOrder, nameDisplayOrder: PresentationPersonNameOrder) { if theme !== self.currentState.presentationData.theme || strings !== self.currentState.presentationData.strings || timeFormat != self.currentState.presentationData.timeFormat { self.theme = theme @@ -775,7 +775,7 @@ final class ChatListNode: ListView { } self.updateState { - return $0.withUpdatedPresentationData(ChatListPresentationData(theme: theme, strings: strings, timeFormat: timeFormat)) + return $0.withUpdatedPresentationData(ChatListPresentationData(theme: theme, strings: strings, timeFormat: timeFormat, nameSortOrder: nameSortOrder, nameDisplayOrder: nameDisplayOrder)) } } } diff --git a/TelegramUI/ChatListPresentationData.swift b/TelegramUI/ChatListPresentationData.swift index 8bcab322f0..5978e5d2c9 100644 --- a/TelegramUI/ChatListPresentationData.swift +++ b/TelegramUI/ChatListPresentationData.swift @@ -4,10 +4,14 @@ final class ChatListPresentationData { let theme: PresentationTheme let strings: PresentationStrings let timeFormat: PresentationTimeFormat + let nameSortOrder: PresentationPersonNameOrder + let nameDisplayOrder: PresentationPersonNameOrder - init(theme: PresentationTheme, strings: PresentationStrings, timeFormat: PresentationTimeFormat) { + init(theme: PresentationTheme, strings: PresentationStrings, timeFormat: PresentationTimeFormat, nameSortOrder: PresentationPersonNameOrder, nameDisplayOrder: PresentationPersonNameOrder) { self.theme = theme self.strings = strings self.timeFormat = timeFormat + self.nameSortOrder = nameSortOrder + self.nameDisplayOrder = nameDisplayOrder } } diff --git a/TelegramUI/ChatListSearchContainerNode.swift b/TelegramUI/ChatListSearchContainerNode.swift index fd07d75fd8..cad29ddfa3 100644 --- a/TelegramUI/ChatListSearchContainerNode.swift +++ b/TelegramUI/ChatListSearchContainerNode.swift @@ -38,13 +38,13 @@ private enum ChatListRecentEntryStableId: Hashable { private enum ChatListRecentEntry: Comparable, Identifiable { case topPeers([Peer], PresentationTheme, PresentationStrings) - case peer(index: Int, peer: RecentlySearchedPeer, PresentationTheme, PresentationStrings, PresentationTimeFormat, Bool) + case peer(index: Int, peer: RecentlySearchedPeer, PresentationTheme, PresentationStrings, PresentationTimeFormat, PresentationPersonNameOrder, PresentationPersonNameOrder, Bool) var stableId: ChatListRecentEntryStableId { switch self { case .topPeers: return .topPeers - case let .peer(_, peer, _, _, _, _): + case let .peer(_, peer, _, _, _, _, _, _): return .peerId(peer.peer.peerId) } } @@ -71,8 +71,8 @@ private enum ChatListRecentEntry: Comparable, Identifiable { } else { return false } - case let .peer(lhsIndex, lhsPeer, lhsTheme, lhsStrings, lhsTimeFormat, lhsHasRevealControls): - if case let .peer(rhsIndex, rhsPeer, rhsTheme, rhsStrings, rhsTimeFormat, rhsHasRevealControls) = rhs, lhsPeer == rhsPeer && lhsIndex == rhsIndex, lhsTheme === rhsTheme, lhsStrings === rhsStrings && lhsTimeFormat == rhsTimeFormat && lhsHasRevealControls == rhsHasRevealControls { + case let .peer(lhsIndex, lhsPeer, lhsTheme, lhsStrings, lhsTimeFormat, lhsSortOrder, lhsDisplayOrder, lhsHasRevealControls): + if case let .peer(rhsIndex, rhsPeer, rhsTheme, rhsStrings, rhsTimeFormat, rhsSortOrder, rhsDisplayOrder, rhsHasRevealControls) = rhs, lhsPeer == rhsPeer && lhsIndex == rhsIndex, lhsTheme === rhsTheme, lhsStrings === rhsStrings && lhsTimeFormat == rhsTimeFormat && lhsSortOrder == rhsSortOrder && lhsDisplayOrder == rhsDisplayOrder && lhsHasRevealControls == rhsHasRevealControls { return true } else { return false @@ -84,11 +84,11 @@ private enum ChatListRecentEntry: Comparable, Identifiable { switch lhs { case .topPeers: return true - case let .peer(lhsIndex, _, _, _, _, _): + case let .peer(lhsIndex, _, _, _, _, _, _, _): switch rhs { case .topPeers: return false - case let .peer(rhsIndex, _, _, _, _, _): + case let .peer(rhsIndex, _, _, _, _, _, _, _): return lhsIndex <= rhsIndex } } @@ -102,7 +102,7 @@ private enum ChatListRecentEntry: Comparable, Identifiable { }, peerLongTapped: { peer in peerLongTapped(peer) }) - case let .peer(_, peer, theme, strings, timeFormat, hasRevealControls): + case let .peer(_, peer, theme, strings, timeFormat, nameSortOrder, nameDisplayOrder, hasRevealControls): let primaryPeer: Peer var chatPeer: Peer? let maybeChatPeer = peer.peer.peers[peer.peer.peerId]! @@ -180,7 +180,7 @@ private enum ChatListRecentEntry: Comparable, Identifiable { badge = ContactsPeerItemBadge(count: peer.unreadCount, type: isMuted ? .inactive : .active) } - return ContactsPeerItem(theme: theme, strings: strings, account: account, peerMode: .generalSearch, peer: .peer(peer: primaryPeer, chatPeer: chatPeer), status: status, badge: badge, enabled: enabled, selection: .none, editing: ContactsPeerItemEditing(editable: true, editing: false, revealed: hasRevealControls), index: nil, header: ChatListSearchItemHeader(type: .recentPeers, theme: theme, strings: strings, actionTitle: strings.WebSearch_RecentSectionClear.uppercased(), action: { + return ContactsPeerItem(theme: theme, strings: strings, sortOrder: nameSortOrder, displayOrder: nameDisplayOrder, account: account, peerMode: .generalSearch, peer: .peer(peer: primaryPeer, chatPeer: chatPeer), status: status, badge: badge, enabled: enabled, selection: .none, editing: ContactsPeerItemEditing(editable: true, editing: false, revealed: hasRevealControls), index: nil, header: ChatListSearchItemHeader(type: .recentPeers, theme: theme, strings: strings, actionTitle: strings.WebSearch_RecentSectionClear.uppercased(), action: { clearRecentlySearchedPeers() }), action: { _ in if let chatPeer = peer.peer.peers[peer.peer.peerId] { @@ -233,15 +233,15 @@ enum ChatListSearchEntryStableId: Hashable { enum ChatListSearchEntry: Comparable, Identifiable { - case localPeer(Peer, Peer?, UnreadSearchBadge?, Int, PresentationTheme, PresentationStrings) - case globalPeer(FoundPeer, UnreadSearchBadge?, Int, PresentationTheme, PresentationStrings) + case localPeer(Peer, Peer?, UnreadSearchBadge?, Int, PresentationTheme, PresentationStrings, PresentationPersonNameOrder, PresentationPersonNameOrder) + case globalPeer(FoundPeer, UnreadSearchBadge?, Int, PresentationTheme, PresentationStrings, PresentationPersonNameOrder, PresentationPersonNameOrder) case message(Message, CombinedPeerReadState?, ChatListPresentationData) var stableId: ChatListSearchEntryStableId { switch self { - case let .localPeer(peer, _, _, _, _, _): + case let .localPeer(peer, _, _, _, _, _, _, _): return .localPeerId(peer.id) - case let .globalPeer(peer, _, _, _, _): + case let .globalPeer(peer, _, _, _, _, _, _): return .globalPeerId(peer.peer.id) case let .message(message, _, _): return .messageId(message.id) @@ -250,14 +250,14 @@ enum ChatListSearchEntry: Comparable, Identifiable { static func ==(lhs: ChatListSearchEntry, rhs: ChatListSearchEntry) -> Bool { switch lhs { - case let .localPeer(lhsPeer, lhsAssociatedPeer, lhsUnreadBadge, lhsIndex, lhsTheme, lhsStrings): - if case let .localPeer(rhsPeer, rhsAssociatedPeer, rhsUnreadBasge, rhsIndex, rhsTheme, rhsStrings) = rhs, lhsPeer.isEqual(rhsPeer) && arePeersEqual(lhsAssociatedPeer, rhsAssociatedPeer) && lhsIndex == rhsIndex && lhsTheme === rhsTheme && lhsStrings === rhsStrings && lhsUnreadBadge == rhsUnreadBasge { + case let .localPeer(lhsPeer, lhsAssociatedPeer, lhsUnreadBadge, lhsIndex, lhsTheme, lhsStrings, lhsSortOrder, lhsDisplayOrder): + if case let .localPeer(rhsPeer, rhsAssociatedPeer, rhsUnreadBadge, rhsIndex, rhsTheme, rhsStrings, rhsSortOrder, rhsDisplayOrder) = rhs, lhsPeer.isEqual(rhsPeer) && arePeersEqual(lhsAssociatedPeer, rhsAssociatedPeer) && lhsIndex == rhsIndex && lhsTheme === rhsTheme && lhsStrings === rhsStrings && lhsSortOrder == rhsSortOrder && lhsDisplayOrder == rhsDisplayOrder && lhsUnreadBadge == rhsUnreadBadge { return true } else { return false } - case let .globalPeer(lhsPeer, lhsUnreadBadge, lhsIndex, lhsTheme, lhsStrings): - if case let .globalPeer(rhsPeer, rhsUnreadBadge, rhsIndex, rhsTheme, rhsStrings) = rhs, lhsPeer == rhsPeer && lhsIndex == rhsIndex && lhsTheme === rhsTheme && lhsStrings === rhsStrings && lhsUnreadBadge == rhsUnreadBadge { + case let .globalPeer(lhsPeer, lhsUnreadBadge, lhsIndex, lhsTheme, lhsStrings, lhsSortOrder, lhsDisplayOrder): + if case let .globalPeer(rhsPeer, rhsUnreadBadge, rhsIndex, rhsTheme, rhsStrings, rhsSortOrder, rhsDisplayOrder) = rhs, lhsPeer == rhsPeer && lhsIndex == rhsIndex && lhsTheme === rhsTheme && lhsStrings === rhsStrings && lhsSortOrder == rhsSortOrder && lhsDisplayOrder == rhsDisplayOrder && lhsUnreadBadge == rhsUnreadBadge { return true } else { return false @@ -285,17 +285,17 @@ enum ChatListSearchEntry: Comparable, Identifiable { static func <(lhs: ChatListSearchEntry, rhs: ChatListSearchEntry) -> Bool { switch lhs { - case let .localPeer(_, _, _, lhsIndex, _, _): - if case let .localPeer(_, _, _, rhsIndex, _, _) = rhs { + case let .localPeer(_, _, _, lhsIndex, _, _, _, _): + if case let .localPeer(_, _, _, rhsIndex, _, _, _, _) = rhs { return lhsIndex <= rhsIndex } else { return true } - case let .globalPeer(_, _, lhsIndex, _, _): + case let .globalPeer(_, _, lhsIndex, _, _, _, _): switch rhs { case .localPeer: return false - case let .globalPeer(_, _, rhsIndex, _, _): + case let .globalPeer(_, _, rhsIndex, _, _, _, _): return lhsIndex <= rhsIndex case .message: return true @@ -311,7 +311,7 @@ enum ChatListSearchEntry: Comparable, Identifiable { func item(account: Account, enableHeaders: Bool, filter: ChatListNodePeersFilter, interaction: ChatListNodeInteraction) -> ListViewItem { switch self { - case let .localPeer(peer, associatedPeer, unreadBadge, _, theme, strings): + case let .localPeer(peer, associatedPeer, unreadBadge, _, theme, strings, nameSortOrder, nameDisplayOrder): let primaryPeer: Peer var chatPeer: Peer? if let associatedPeer = associatedPeer { @@ -356,10 +356,10 @@ enum ChatListSearchEntry: Comparable, Identifiable { badge = ContactsPeerItemBadge(count: unreadBadge.count, type: unreadBadge.isMuted ? .inactive : .active) } - return ContactsPeerItem(theme: theme, strings: strings, account: account, peerMode: .generalSearch, peer: .peer(peer: primaryPeer, chatPeer: chatPeer), status: .none, badge: badge, enabled: enabled, selection: .none, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), index: nil, header: ChatListSearchItemHeader(type: .localPeers, theme: theme, strings: strings, actionTitle: nil, action: nil), action: { _ in + return ContactsPeerItem(theme: theme, strings: strings, sortOrder: nameSortOrder, displayOrder: nameDisplayOrder, account: account, peerMode: .generalSearch, peer: .peer(peer: primaryPeer, chatPeer: chatPeer), status: .none, badge: badge, enabled: enabled, selection: .none, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), index: nil, header: ChatListSearchItemHeader(type: .localPeers, theme: theme, strings: strings, actionTitle: nil, action: nil), action: { _ in interaction.peerSelected(peer) }) - case let .globalPeer(peer, unreadBadge, _, theme, strings): + case let .globalPeer(peer, unreadBadge, _, theme, strings, nameSortOrder, nameDisplayOrder): var enabled = true if filter.contains(.onlyWriteable) { enabled = canSendMessagesToPeer(peer.peer) @@ -393,7 +393,7 @@ enum ChatListSearchEntry: Comparable, Identifiable { badge = ContactsPeerItemBadge(count: unreadBadge.count, type: unreadBadge.isMuted ? .inactive : .active) } - return ContactsPeerItem(theme: theme, strings: strings, account: account, peerMode: .generalSearch, peer: .peer(peer: peer.peer, chatPeer: peer.peer), status: .addressName(suffixString), badge: badge, enabled: enabled, selection: .none, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), index: nil, header: ChatListSearchItemHeader(type: .globalPeers, theme: theme, strings: strings, actionTitle: nil, action: nil), action: { _ in + return ContactsPeerItem(theme: theme, strings: strings, sortOrder: nameSortOrder, displayOrder: nameDisplayOrder, account: account, peerMode: .generalSearch, peer: .peer(peer: peer.peer, chatPeer: peer.peer), status: .addressName(suffixString), badge: badge, enabled: enabled, selection: .none, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), index: nil, header: ChatListSearchItemHeader(type: .globalPeers, theme: theme, strings: strings, actionTitle: nil, action: nil), action: { _ in interaction.peerSelected(peer.peer) }) case let .message(message, readState, presentationData): @@ -506,7 +506,7 @@ final class ChatListSearchContainerNode: SearchDisplayControllerContentNode { self.openMessage = openMessage self.presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 } - self.presentationDataPromise = Promise(ChatListPresentationData(theme: self.presentationData.theme, strings: self.presentationData.strings, timeFormat: self.presentationData.timeFormat)) + self.presentationDataPromise = Promise(ChatListPresentationData(theme: self.presentationData.theme, strings: self.presentationData.strings, timeFormat: self.presentationData.timeFormat, nameSortOrder: self.presentationData.nameSortOrder, nameDisplayOrder: self.presentationData.nameDisplayOrder)) self.recentListNode = ListView() self.listNode = ListView() @@ -526,13 +526,15 @@ final class ChatListSearchContainerNode: SearchDisplayControllerContentNode { let foundItems = searchQuery.get() |> mapToSignal { query -> Signal<([ChatListSearchEntry], Bool)?, NoError> in if let query = query, !query.isEmpty { - let accountPeer = account.postbox.loadedPeerWithId(account.peerId) |> take(1) + let accountPeer = account.postbox.loadedPeerWithId(account.peerId) + |> take(1) let foundLocalPeers = account.postbox.searchPeers(query: query.lowercased(), groupId: groupId) |> mapToSignal { local -> Signal<([PeerView], [RenderedPeer]), NoError> in return combineLatest(local.map {account.postbox.peerView(id: $0.peerId)}) |> map { views in return (views, local) } - } |> mapToSignal{ viewsAndPeers -> Signal<(peers: [RenderedPeer], unread: [PeerId : UnreadSearchBadge]), NoError> in + } + |> mapToSignal{ viewsAndPeers -> Signal<(peers: [RenderedPeer], unread: [PeerId : UnreadSearchBadge]), NoError> in return account.postbox.unreadMessageCountsView(items: viewsAndPeers.0.map {.peer($0.peerId)}) |> map { values in var unread:[PeerId: UnreadSearchBadge] = [:] for peerView in viewsAndPeers.0 { @@ -554,8 +556,6 @@ final class ChatListSearchContainerNode: SearchDisplayControllerContentNode { } } - - let foundRemotePeers: Signal<([FoundPeer], [FoundPeer], Bool), NoError> if groupId == nil { foundRemotePeers = (.single(([], [], true)) |> then(searchPeers(account: account, query: query) |> map { ($0.0, $0.1, false) } @@ -570,8 +570,8 @@ final class ChatListSearchContainerNode: SearchDisplayControllerContentNode { location = .general } let foundRemoteMessages: Signal<(([Message], [PeerId : CombinedPeerReadState]), Bool), NoError> = .single((([], [:]), true)) |> then(searchMessages(account: account, location: location, query: query) - |> map { ($0, false) } - |> delay(0.2, queue: Queue.concurrentDefaultQueue())) + |> map { ($0, false) } + |> delay(0.2, queue: Queue.concurrentDefaultQueue())) return combineLatest(accountPeer, foundLocalPeers, foundRemotePeers, foundRemoteMessages, presentationDataPromise.get()) |> map { accountPeer, foundLocalPeers, foundRemotePeers, foundRemoteMessages, presentationData -> ([ChatListSearchEntry], Bool)? in @@ -584,7 +584,7 @@ final class ChatListSearchContainerNode: SearchDisplayControllerContentNode { if presentationData.strings.DialogList_SavedMessages.lowercased().hasPrefix(query.lowercased()) { if !existingPeerIds.contains(accountPeer.id) { existingPeerIds.insert(accountPeer.id) - entries.append(.localPeer(accountPeer, nil, nil, index, presentationData.theme, presentationData.strings)) + entries.append(.localPeer(accountPeer, nil, nil, index, presentationData.theme, presentationData.strings, presentationData.nameSortOrder, presentationData.nameDisplayOrder)) index += 1 } } @@ -597,7 +597,7 @@ final class ChatListSearchContainerNode: SearchDisplayControllerContentNode { if let associatedPeerId = peer.associatedPeerId { associatedPeer = renderedPeer.peers[associatedPeerId] } - entries.append(.localPeer(peer, associatedPeer, foundLocalPeers.unread[peer.id], index, presentationData.theme, presentationData.strings)) + entries.append(.localPeer(peer, associatedPeer, foundLocalPeers.unread[peer.id], index, presentationData.theme, presentationData.strings, presentationData.nameSortOrder, presentationData.nameDisplayOrder)) index += 1 } } @@ -606,7 +606,7 @@ final class ChatListSearchContainerNode: SearchDisplayControllerContentNode { for peer in foundRemotePeers.0 { if !existingPeerIds.contains(peer.peer.id) { existingPeerIds.insert(peer.peer.id) - entries.append(.localPeer(peer.peer, nil, nil, index, presentationData.theme, presentationData.strings)) + entries.append(.localPeer(peer.peer, nil, nil, index, presentationData.theme, presentationData.strings, presentationData.nameSortOrder, presentationData.nameDisplayOrder)) index += 1 } } @@ -615,7 +615,7 @@ final class ChatListSearchContainerNode: SearchDisplayControllerContentNode { for peer in foundRemotePeers.1 { if !existingPeerIds.contains(peer.peer.id) { existingPeerIds.insert(peer.peer.id) - entries.append(.globalPeer(peer, nil, index, presentationData.theme, presentationData.strings)) + entries.append(.globalPeer(peer, nil, index, presentationData.theme, presentationData.strings, presentationData.nameSortOrder, presentationData.nameDisplayOrder)) index += 1 } } @@ -696,7 +696,7 @@ final class ChatListSearchContainerNode: SearchDisplayControllerContentNode { } peerIds.insert(peer.id) - entries.append(.peer(index: index, peer: searchedPeer, presentationData.theme, presentationData.strings, presentationData.timeFormat, state.peerIdWithRevealedOptions == peer.id)) + entries.append(.peer(index: index, peer: searchedPeer, presentationData.theme, presentationData.strings, presentationData.timeFormat, presentationData.nameSortOrder, presentationData.nameDisplayOrder, state.peerIdWithRevealedOptions == peer.id)) index += 1 } } diff --git a/TelegramUI/ChatMessageActionItemNode.swift b/TelegramUI/ChatMessageActionItemNode.swift index e646a7fb39..f67674d0db 100644 --- a/TelegramUI/ChatMessageActionItemNode.swift +++ b/TelegramUI/ChatMessageActionItemNode.swift @@ -158,22 +158,10 @@ private func universalServiceMessageString(theme: PresentationTheme?, strings: P type = .video } break inner - case let .Audio(isVoice, _, performer, title, _): + case let .Audio(isVoice, _, _, _, _): if isVoice { type = .audio } else { -// let descriptionString: String -// if let title = title, let performer = performer, !title.isEmpty, !performer.isEmpty { -// descriptionString = title + " — " + performer -// } else if let title = title, !title.isEmpty { -// descriptionString = title -// } else if let performer = performer, !performer.isEmpty { -// descriptionString = performer -// } else if let fileName = file.fileName { -// descriptionString = strings.Message_File -// } else { -// descriptionString = strings.Message_Audio -// } type = .file } break inner @@ -203,7 +191,13 @@ private func universalServiceMessageString(theme: PresentationTheme?, strings: P if clippedText.count > 14 { clippedText = "\(clippedText[...clippedText.index(clippedText.startIndex, offsetBy: 14)])..." } - attributedString = addAttributesToStringWithRanges(strings.Notification_PinnedTextMessage(authorName, clippedText), body: bodyAttributes, argumentAttributes: peerMentionsAttributes(primaryTextColor: primaryTextColor, peerIds: [(0, message.author?.id)])) + let textWithRanges: (String, [(Int, NSRange)]) + if clippedText.isEmpty { + textWithRanges = strings.PINNED_NOTEXT(authorName) + } else { + textWithRanges = strings.Notification_PinnedTextMessage(authorName, clippedText) + } + attributedString = addAttributesToStringWithRanges(textWithRanges, body: bodyAttributes, argumentAttributes: peerMentionsAttributes(primaryTextColor: primaryTextColor, peerIds: [(0, message.author?.id)])) case .game: attributedString = addAttributesToStringWithRanges(strings.PINNED_GAME(authorName), body: bodyAttributes, argumentAttributes: peerMentionsAttributes(primaryTextColor: primaryTextColor, peerIds: [(0, message.author?.id)])) case .photo: @@ -225,7 +219,7 @@ private func universalServiceMessageString(theme: PresentationTheme?, strings: P case .contact: attributedString = addAttributesToStringWithRanges(strings.Notification_PinnedContactMessage(authorName), body: bodyAttributes, argumentAttributes: peerMentionsAttributes(primaryTextColor: primaryTextColor, peerIds: [(0, message.author?.id)])) case .deleted: - attributedString = addAttributesToStringWithRanges(strings.Notification_PinnedDeletedMessage(authorName), body: bodyAttributes, argumentAttributes: peerMentionsAttributes(primaryTextColor: primaryTextColor, peerIds: [(0, message.author?.id)])) + attributedString = addAttributesToStringWithRanges(strings.PINNED_NOTEXT(authorName), body: bodyAttributes, argumentAttributes: peerMentionsAttributes(primaryTextColor: primaryTextColor, peerIds: [(0, message.author?.id)])) } case .joinedByLink: attributedString = addAttributesToStringWithRanges(strings.Notification_JoinedGroupByLink(authorName), body: bodyAttributes, argumentAttributes: peerMentionsAttributes(primaryTextColor: primaryTextColor, peerIds: [(0, message.author?.id)])) diff --git a/TelegramUI/ChatMessageBubbleItemNode.swift b/TelegramUI/ChatMessageBubbleItemNode.swift index e7e3ab20de..0eef850a7e 100644 --- a/TelegramUI/ChatMessageBubbleItemNode.swift +++ b/TelegramUI/ChatMessageBubbleItemNode.swift @@ -387,14 +387,14 @@ class ChatMessageBubbleItemNode: ChatMessageItemView { } if let info = item.message.forwardInfo { - if let author = info.author as? TelegramUser, let _ = author.botInfo { + if let author = info.author as? TelegramUser, let _ = author.botInfo, !item.message.media.isEmpty && !(item.message.media.first is TelegramMediaAction) { needShareButton = true - } else if let author = info.author as? TelegramChannel, case .broadcast = author.info, !(item.message.media.first is TelegramMediaAction) { + } else if let author = info.author as? TelegramChannel, case .broadcast = author.info { needShareButton = true } } - if !needShareButton, let author = item.message.author as? TelegramUser, let _ = author.botInfo, !(item.message.media.first is TelegramMediaAction) { + if !needShareButton, let author = item.message.author as? TelegramUser, let _ = author.botInfo, !item.message.media.isEmpty && !(item.message.media.first is TelegramMediaAction) { needShareButton = true } if !needShareButton { diff --git a/TelegramUI/ChatMessageNotificationItem.swift b/TelegramUI/ChatMessageNotificationItem.swift index eb0956473b..efb10dfc05 100644 --- a/TelegramUI/ChatMessageNotificationItem.swift +++ b/TelegramUI/ChatMessageNotificationItem.swift @@ -8,18 +8,18 @@ import SwiftSignalKit public final class ChatMessageNotificationItem: NotificationItem { let account: Account let strings: PresentationStrings - let message: Message + let messages: [Message] let tapAction: () -> Bool let expandAction: (@escaping () -> (ASDisplayNode?, () -> Void)) -> Void public var groupingKey: AnyHashable? { - return message.id.peerId + return messages.first?.id.peerId } - public init(account: Account, strings: PresentationStrings, message: Message, tapAction: @escaping () -> Bool, expandAction: @escaping (() -> (ASDisplayNode?, () -> Void)) -> Void) { + public init(account: Account, strings: PresentationStrings, messages: [Message], tapAction: @escaping () -> Bool, expandAction: @escaping (() -> (ASDisplayNode?, () -> Void)) -> Void) { self.account = account self.strings = strings - self.message = message + self.messages = messages self.tapAction = tapAction self.expandAction = expandAction } @@ -90,30 +90,30 @@ final class ChatMessageNotificationItemNode: NotificationItemNode { self.item = item let presentationData = item.account.telegramApplicationContext.currentPresentationData.with { $0 } - if let peer = messageMainPeer(item.message) { + var title: String? + if let firstMessage = item.messages.first, let peer = messageMainPeer(firstMessage) { self.avatarNode.setPeer(account: item.account, peer: peer) if let channel = peer as? TelegramChannel, case .broadcast = channel.info { - self.titleAttributedText = NSAttributedString(string: peer.displayTitle, font: Font.semibold(16.0), textColor: presentationData.theme.inAppNotification.primaryTextColor) - } else if let author = item.message.author, author.id != peer.id { - self.titleAttributedText = NSAttributedString(string: author.displayTitle + "@" + peer.displayTitle, font: Font.semibold(16.0), textColor: presentationData.theme.inAppNotification.primaryTextColor) + title = peer.displayTitle + } else if let author = firstMessage.author, author.id != peer.id { + title = author.displayTitle + "@" + peer.displayTitle } else { - self.titleAttributedText = NSAttributedString(string: peer.displayTitle, font: Font.semibold(16.0), textColor: presentationData.theme.inAppNotification.primaryTextColor) + title = peer.displayTitle } } var titleIcon: UIImage? - if item.message.id.peerId.namespace == Namespaces.Peer.SecretChat { - titleIcon = PresentationResourcesRootController.inAppNotificationSecretChatIcon(presentationData.theme) - } - - self.titleIconNode.image = titleIcon - var updatedMedia: Media? var imageDimensions: CGSize? var isRound = false - if item.message.id.peerId.namespace != Namespaces.Peer.SecretChat { - for media in item.message.media { + let messageText: String + if item.messages.first?.id.peerId.namespace == Namespaces.Peer.SecretChat { + titleIcon = PresentationResourcesRootController.inAppNotificationSecretChatIcon(presentationData.theme) + messageText = item.strings.ENCRYPTED_MESSAGE("").0 + } else if item.messages.count == 1 { + let message = item.messages[0] + for media in message.media { if let image = media as? TelegramMediaImage { updatedMedia = image if let representation = largestRepresentationForPhoto(image) { @@ -129,11 +129,82 @@ final class ChatMessageNotificationItemNode: NotificationItemNode { break } } + if message.containsSecretMedia { + imageDimensions = nil + } + messageText = descriptionStringForMessage(message, strings: item.strings, accountPeerId: item.account.peerId).0 + } else if item.messages.count > 1, let peer = item.messages[0].peers[item.messages[0].id.peerId] { + var displayAuthor = true + if let channel = peer as? TelegramChannel { + switch channel.info { + case .group: + displayAuthor = true + case .broadcast: + displayAuthor = false + } + } else if let _ = peer as? TelegramUser { + displayAuthor = false + } + + if item.messages[0].forwardInfo != nil { + if let author = item.messages[0].author, displayAuthor { + title = nil + messageText = presentationData.strings.CHAT_MESSAGE_FWDS(author.compactDisplayTitle, peer.displayTitle, "\(item.messages.count)").0 + } else { + title = nil + messageText = presentationData.strings.MESSAGE_FWDS(peer.displayTitle, "\(item.messages.count)").0 + } + } else if item.messages[0].groupingKey != nil { + var kind = messageContentKind(item.messages[0], strings: presentationData.strings, accountPeerId: item.account.peerId).key + for i in 1 ..< item.messages.count { + let nextKind = messageContentKind(item.messages[i], strings: presentationData.strings, accountPeerId: item.account.peerId) + if kind != nextKind.key { + kind = .text + break + } + } + var isChannel = false + var isGroup = false + if let peer = peer as? TelegramChannel { + if case .broadcast = peer.info { + isChannel = true + } else { + isGroup = true + } + } else if item.messages[0].id.peerId.namespace == Namespaces.Peer.CloudGroup { + isGroup = true + } + title = nil + if isChannel { + switch kind { + case .image: + messageText = presentationData.strings.CHANNEL_MESSAGE_PHOTOS(peer.compactDisplayTitle, "\(item.messages.count)").0 + default: + messageText = presentationData.strings.CHANNEL_MESSAGES(peer.compactDisplayTitle, "\(item.messages.count)").0 + } + } else if isGroup, let author = item.messages[0].author { + switch kind { + case .image: + messageText = presentationData.strings.CHAT_MESSAGE_PHOTOS(author.compactDisplayTitle, peer.displayTitle, "\(item.messages.count)").0 + default: + messageText = presentationData.strings.CHAT_MESSAGES(author.compactDisplayTitle, peer.displayTitle, "\(item.messages.count)").0 + } + } else { + switch kind { + case .image: + messageText = presentationData.strings.MESSAGE_PHOTOS(peer.displayTitle, "\(item.messages.count)").0 + default: + messageText = presentationData.strings.MESSAGES(peer.displayTitle, "\(item.messages.count)").0 + } + } + } else { + messageText = "" + } + } else { + messageText = "" } - if item.message.containsSecretMedia { - imageDimensions = nil - } + self.titleAttributedText = NSAttributedString(string: title ?? "", font: Font.semibold(16.0), textColor: presentationData.theme.inAppNotification.primaryTextColor) let imageNodeLayout = self.imageNode.asyncLayout() var applyImage: (() -> Void)? @@ -147,25 +218,18 @@ final class ChatMessageNotificationItemNode: NotificationItemNode { } var updateImageSignal: Signal<(TransformImageArguments) -> DrawingContext?, NoError>? - if let updatedMedia = updatedMedia, imageDimensions != nil { + if let firstMessage = item.messages.first, let updatedMedia = updatedMedia, imageDimensions != nil { if let image = updatedMedia as? TelegramMediaImage { - updateImageSignal = mediaGridMessagePhoto(account: item.account, photoReference: .message(message: MessageReference(item.message), media: image)) + updateImageSignal = mediaGridMessagePhoto(account: item.account, photoReference: .message(message: MessageReference(firstMessage), media: image)) } else if let file = updatedMedia as? TelegramMediaFile { if file.isSticker { updateImageSignal = chatMessageSticker(account: item.account, file: file, small: true, fetched: true) } else if file.isVideo { - updateImageSignal = mediaGridMessageVideo(postbox: item.account.postbox, videoReference: .message(message: MessageReference(item.message), media: file)) + updateImageSignal = mediaGridMessageVideo(postbox: item.account.postbox, videoReference: .message(message: MessageReference(firstMessage), media: file)) } } } - let messageText: String - if item.message.id.peerId.namespace == Namespaces.Peer.SecretChat { - messageText = item.strings.ENCRYPTED_MESSAGE("").0 - } else { - messageText = descriptionStringForMessage(item.message, strings: item.strings, accountPeerId: item.account.peerId).0 - } - if let applyImage = applyImage { applyImage() self.imageNode.isHidden = false diff --git a/TelegramUI/ChatRecentActionsControllerNode.swift b/TelegramUI/ChatRecentActionsControllerNode.swift index 842c1616cc..2d4d878e81 100644 --- a/TelegramUI/ChatRecentActionsControllerNode.swift +++ b/TelegramUI/ChatRecentActionsControllerNode.swift @@ -546,7 +546,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode { text = strongSelf.presentationData.strings.Channel_AdminLog_EmptyFilterQueryText(query).0 } else { - text = isSupergroup ? strongSelf.presentationData.strings.Group_AdminLog_EmptyText : strongSelf.presentationData.strings.Channel_AdminLog_EmptyText + text = isSupergroup ? strongSelf.presentationData.strings.Group_AdminLog_EmptyText : strongSelf.presentationData.strings.Broadcast_AdminLog_EmptyText } strongSelf.emptyNode.setup(title: hasFilter ? strongSelf.presentationData.strings.Channel_AdminLog_EmptyFilterTitle : strongSelf.presentationData.strings.Channel_AdminLog_EmptyTitle, text: text) diff --git a/TelegramUI/ContactListNode.swift b/TelegramUI/ContactListNode.swift index 254007d7dd..7699177e84 100644 --- a/TelegramUI/ContactListNode.swift +++ b/TelegramUI/ContactListNode.swift @@ -118,7 +118,7 @@ enum ContactListPeer: Equatable { private enum ContactListNodeEntry: Comparable, Identifiable { case search(PresentationTheme, PresentationStrings) case option(Int, ContactListAdditionalOption, PresentationTheme, PresentationStrings) - case peer(Int, ContactListPeer, PeerPresence?, ListViewItemHeader?, ContactsPeerItemSelection, PresentationTheme, PresentationStrings, PresentationTimeFormat, Bool) + case peer(Int, ContactListPeer, PeerPresence?, ListViewItemHeader?, ContactsPeerItemSelection, PresentationTheme, PresentationStrings, PresentationTimeFormat, PresentationPersonNameOrder, PresentationPersonNameOrder, Bool) var stableId: ContactListNodeEntryId { switch self { @@ -126,7 +126,7 @@ private enum ContactListNodeEntry: Comparable, Identifiable { return .search case let .option(index, _, _, _): return .option(index: index) - case let .peer(_, peer, _, _, _, _, _, _, _): + case let .peer(_, peer, _, _, _, _, _, _, _, _, _): switch peer { case let .peer(peer, _): return .peerId(peer.id.toInt64()) @@ -139,12 +139,12 @@ private enum ContactListNodeEntry: Comparable, Identifiable { func item(account: Account, interaction: ContactListNodeInteraction) -> ListViewItem { switch self { case let .search(theme, strings): - return ChatListSearchItem(theme: theme, placeholder: strings.Common_Search, activate: { + return ChatListSearchItem(theme: theme, placeholder: strings.Contacts_SearchLabel, activate: { interaction.activateSearch() }) case let .option(_, option, theme, _): return ContactListActionItem(theme: theme, title: option.title, icon: option.icon, action: option.action) - case let .peer(_, peer, presence, header, selection, theme, strings, timeFormat, enabled): + case let .peer(_, peer, presence, header, selection, theme, strings, timeFormat, nameSortOrder, nameDisplayOrder, enabled): let status: ContactsPeerItemStatus let itemPeer: ContactsPeerItemPeer switch peer { @@ -161,7 +161,7 @@ private enum ContactListNodeEntry: Comparable, Identifiable { status = .none itemPeer = .deviceContact(stableId: id, contact: contact) } - return ContactsPeerItem(theme: theme, strings: strings, account: account, peerMode: .peer, peer: itemPeer, status: status, enabled: enabled, selection: selection, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), index: nil, header: header, action: { _ in + return ContactsPeerItem(theme: theme, strings: strings, sortOrder: nameSortOrder, displayOrder: nameDisplayOrder, account: account, peerMode: .peer, peer: itemPeer, status: status, enabled: enabled, selection: selection, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), index: nil, header: header, action: { _ in interaction.openPeer(peer) }) } @@ -181,9 +181,9 @@ private enum ContactListNodeEntry: Comparable, Identifiable { } else { return false } - case let .peer(lhsIndex, lhsPeer, lhsPresence, lhsHeader, lhsSelection, lhsTheme, lhsStrings, lhsTimeFormat, lhsEnabled): + case let .peer(lhsIndex, lhsPeer, lhsPresence, lhsHeader, lhsSelection, lhsTheme, lhsStrings, lhsTimeFormat, lhsSortOrder, lhsDisplayOrder, lhsEnabled): switch rhs { - case let .peer(rhsIndex, rhsPeer, rhsPresence, rhsHeader, rhsSelection, rhsTheme, rhsStrings, rhsTimeFormat, rhsEnabled): + case let .peer(rhsIndex, rhsPeer, rhsPresence, rhsHeader, rhsSelection, rhsTheme, rhsStrings, rhsTimeFormat, rhsSortOrder, rhsDisplayOrder, rhsEnabled): if lhsIndex != rhsIndex { return false } @@ -212,6 +212,12 @@ private enum ContactListNodeEntry: Comparable, Identifiable { if lhsTimeFormat != rhsTimeFormat { return false } + if lhsSortOrder != rhsSortOrder { + return false + } + if lhsDisplayOrder != rhsDisplayOrder { + return false + } if lhsEnabled != rhsEnabled { return false } @@ -235,11 +241,11 @@ private enum ContactListNodeEntry: Comparable, Identifiable { case .peer: return true } - case let .peer(lhsIndex, _, _, _, _, _, _, _, _): + case let .peer(lhsIndex, _, _, _, _, _, _, _, _, _, _): switch rhs { case .search, .option: return false - case let .peer(rhsIndex, _, _, _, _, _, _, _, _): + case let .peer(rhsIndex, _, _, _, _, _, _, _, _, _, _): return lhsIndex < rhsIndex } } @@ -247,7 +253,7 @@ private enum ContactListNodeEntry: Comparable, Identifiable { } private extension PeerIndexNameRepresentation { - func isLessThan(other: PeerIndexNameRepresentation) -> ComparisonResult { + func isLessThan(other: PeerIndexNameRepresentation, ordering: PresentationPersonNameOrder) -> ComparisonResult { switch self { case let .title(lhsTitle, _): switch other { @@ -271,18 +277,28 @@ private extension PeerIndexNameRepresentation { return lastResult } case let .personName(first, last, _, _): - let lastResult = lhsLast.compare(last) - if lastResult == .orderedSame { - return lhsFirst.compare(first) - } else { - return lastResult + switch ordering { + case .firstLast: + let firstResult = lhsFirst.compare(first) + if firstResult == .orderedSame { + return lhsLast.compare(last) + } else { + return firstResult + } + case .lastFirst: + let lastResult = lhsLast.compare(last) + if lastResult == .orderedSame { + return lhsFirst.compare(first) + } else { + return lastResult + } } } } } } -private func contactListNodeEntries(accountPeer: Peer?, peers: [ContactListPeer], presences: [PeerId: PeerPresence], presentation: ContactListPresentation, selectionState: ContactListNodeGroupSelectionState?, theme: PresentationTheme, strings: PresentationStrings, timeFormat: PresentationTimeFormat, disabledPeerIds:Set) -> [ContactListNodeEntry] { +private func contactListNodeEntries(accountPeer: Peer?, peers: [ContactListPeer], presences: [PeerId: PeerPresence], presentation: ContactListPresentation, selectionState: ContactListNodeGroupSelectionState?, theme: PresentationTheme, strings: PresentationStrings, timeFormat: PresentationTimeFormat, sortOrder: PresentationPersonNameOrder, displayOrder: PresentationPersonNameOrder, disabledPeerIds:Set) -> [ContactListNodeEntry] { var entries: [ContactListNodeEntry] = [] var orderedPeers: [ContactListPeer] @@ -318,7 +334,7 @@ private func contactListNodeEntries(accountPeer: Peer?, peers: [ContactListPeer] } case let .natural(displaySearch, options): orderedPeers = peers.sorted(by: { lhs, rhs in - let result = lhs.indexName.isLessThan(other: rhs.indexName) + let result = lhs.indexName.isLessThan(other: rhs.indexName, ordering: sortOrder) if result == .orderedSame { if case let .peer(lhsPeer, _) = lhs, case let .peer(rhsPeer, _) = rhs { return lhsPeer.id < rhsPeer.id @@ -342,10 +358,19 @@ private func contactListNodeEntries(accountPeer: Peer?, peers: [ContactListPeer] indexHeader = c } case let .personName(first, last, _, _): - if let c = last.utf16.first { - indexHeader = c - } else if let c = first.utf16.first { - indexHeader = c + switch sortOrder { + case .firstLast: + if let c = first.utf16.first { + indexHeader = c + } else if let c = last.utf16.first { + indexHeader = c + } + case .lastFirst: + if let c = last.utf16.first { + indexHeader = c + } else if let c = first.utf16.first { + indexHeader = c + } } } let header: ContactListNameIndexHeader @@ -414,12 +439,12 @@ private func contactListNodeEntries(accountPeer: Peer?, peers: [ContactListPeer] } let enabled: Bool switch orderedPeers[i] { - case let .peer(peer, _): - enabled = !disabledPeerIds.contains(peer.id) - default: - enabled = true + case let .peer(peer, _): + enabled = !disabledPeerIds.contains(peer.id) + default: + enabled = true } - entries.append(.peer(i, orderedPeers[i], presence, header, selection, theme, strings, timeFormat, enabled)) + entries.append(.peer(i, orderedPeers[i], presence, header, selection, theme, strings, timeFormat, sortOrder, displayOrder, enabled)) } return entries } @@ -541,7 +566,7 @@ final class ContactListNode: ASDisplayNode { private var presentationData: PresentationData private var presentationDataDisposable: Disposable? - private let themeAndStringsPromise: Promise<(PresentationTheme, PresentationStrings, PresentationTimeFormat)> + private let themeAndStringsPromise: Promise<(PresentationTheme, PresentationStrings, PresentationTimeFormat, PresentationPersonNameOrder, PresentationPersonNameOrder)> init(account: Account, presentation: ContactListPresentation, filters: [ContactListFilter] = [.excludeSelf], selectionState: ContactListNodeGroupSelectionState? = nil) { self.account = account @@ -552,7 +577,7 @@ final class ContactListNode: ASDisplayNode { self.presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 } - self.themeAndStringsPromise = Promise((self.presentationData.theme, self.presentationData.strings, self.presentationData.timeFormat)) + self.themeAndStringsPromise = Promise((self.presentationData.theme, self.presentationData.strings, self.presentationData.timeFormat, self.presentationData.nameSortOrder, self.presentationData.nameDisplayOrder)) super.init() @@ -655,7 +680,7 @@ final class ContactListNode: ASDisplayNode { peers.append(.deviceContact(stableId, contact)) } - let entries = contactListNodeEntries(accountPeer: nil, peers: peers, presences: [:], presentation: presentation, selectionState: selectionState, theme: themeAndStrings.0, strings: themeAndStrings.1, timeFormat: themeAndStrings.2, disabledPeerIds: disabledPeerIds) + let entries = contactListNodeEntries(accountPeer: nil, peers: peers, presences: [:], presentation: presentation, selectionState: selectionState, theme: themeAndStrings.0, strings: themeAndStrings.1, timeFormat: themeAndStrings.2, sortOrder: themeAndStrings.3, displayOrder: themeAndStrings.4, disabledPeerIds: disabledPeerIds) let previous = previousEntries.swap(entries) return .single(preparedContactListNodeTransition(account: account, from: previous ?? [], to: entries, interaction: interaction, firstTime: previous == nil, animated: false)) } @@ -695,7 +720,7 @@ final class ContactListNode: ASDisplayNode { } } - let entries = contactListNodeEntries(accountPeer: view.accountPeer, peers: peers, presences: view.peerPresences, presentation: presentation, selectionState: selectionState, theme: themeAndStrings.0, strings: themeAndStrings.1, timeFormat: themeAndStrings.2, disabledPeerIds: disabledPeerIds) + let entries = contactListNodeEntries(accountPeer: view.accountPeer, peers: peers, presences: view.peerPresences, presentation: presentation, selectionState: selectionState, theme: themeAndStrings.0, strings: themeAndStrings.1, timeFormat: themeAndStrings.2, sortOrder: themeAndStrings.3, displayOrder: themeAndStrings.4, disabledPeerIds: disabledPeerIds) let previous = previousEntries.swap(entries) let animated: Bool if let previous = previous { @@ -728,7 +753,7 @@ final class ContactListNode: ASDisplayNode { if previousTheme !== presentationData.theme || previousStrings !== presentationData.strings { strongSelf.backgroundColor = presentationData.theme.chatList.backgroundColor - strongSelf.themeAndStringsPromise.set(.single((presentationData.theme, presentationData.strings, presentationData.timeFormat))) + strongSelf.themeAndStringsPromise.set(.single((presentationData.theme, presentationData.strings, presentationData.timeFormat, presentationData.nameSortOrder, presentationData.nameDisplayOrder))) strongSelf.listNode.forEachAccessoryItemNode({ accessoryItemNode in if let accessoryItemNode = accessoryItemNode as? ContactsSectionHeaderAccessoryItemNode { diff --git a/TelegramUI/ContactSelectionControllerNode.swift b/TelegramUI/ContactSelectionControllerNode.swift index 84256d665d..c34bfe304a 100644 --- a/TelegramUI/ContactSelectionControllerNode.swift +++ b/TelegramUI/ContactSelectionControllerNode.swift @@ -36,14 +36,13 @@ final class ContactSelectionControllerNode: ASDisplayNode { init(account: Account, options: [ContactListAdditionalOption], displayDeviceContacts: Bool) { self.account = account + self.presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 } self.displayDeviceContacts = displayDeviceContacts self.contactListNode = ContactListNode(account: account, presentation: .natural(displaySearch: true, options: options)) self.dimNode = ASDisplayNode() - self.presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 } - super.init() self.setViewBlock({ diff --git a/TelegramUI/ContactsPeerItem.swift b/TelegramUI/ContactsPeerItem.swift index dbb38ca7f4..81f4c0049b 100644 --- a/TelegramUI/ContactsPeerItem.swift +++ b/TelegramUI/ContactsPeerItem.swift @@ -108,6 +108,8 @@ enum ContactsPeerItemPeer: Equatable { class ContactsPeerItem: ListViewItem { let theme: PresentationTheme let strings: PresentationStrings + let sortOrder: PresentationPersonNameOrder + let displayOrder: PresentationPersonNameOrder let account: Account let peerMode: ContactsPeerItemPeerMode let peer: ContactsPeerItemPeer @@ -126,9 +128,11 @@ class ContactsPeerItem: ListViewItem { let header: ListViewItemHeader? - init(theme: PresentationTheme, strings: PresentationStrings, account: Account, peerMode: ContactsPeerItemPeerMode, peer: ContactsPeerItemPeer, status: ContactsPeerItemStatus, badge: ContactsPeerItemBadge? = nil, enabled: Bool, selection: ContactsPeerItemSelection, editing: ContactsPeerItemEditing, index: PeerNameIndex?, header: ListViewItemHeader?, action: @escaping (ContactsPeerItemPeer) -> Void, setPeerIdWithRevealedOptions: ((PeerId?, PeerId?) -> Void)? = nil, deletePeer: ((PeerId) -> Void)? = nil) { + init(theme: PresentationTheme, strings: PresentationStrings, sortOrder: PresentationPersonNameOrder, displayOrder: PresentationPersonNameOrder, account: Account, peerMode: ContactsPeerItemPeerMode, peer: ContactsPeerItemPeer, status: ContactsPeerItemStatus, badge: ContactsPeerItemBadge? = nil, enabled: Bool, selection: ContactsPeerItemSelection, editing: ContactsPeerItemEditing, index: PeerNameIndex?, header: ListViewItemHeader?, action: @escaping (ContactsPeerItemPeer) -> Void, setPeerIdWithRevealedOptions: ((PeerId?, PeerId?) -> Void)? = nil, deletePeer: ((PeerId) -> Void)? = nil) { self.theme = theme self.strings = strings + self.sortOrder = sortOrder + self.displayOrder = displayOrder self.account = account self.peerMode = peerMode self.peer = peer @@ -444,9 +448,9 @@ class ContactsPeerItemNode: ItemListRevealOptionsItemNode { titleAttributedString = NSAttributedString(string: item.strings.DialogList_SavedMessages, font: titleBoldFont, textColor: textColor) } else if let firstName = user.firstName, let lastName = user.lastName, !firstName.isEmpty, !lastName.isEmpty { let string = NSMutableAttributedString() - string.append(NSAttributedString(string: firstName, font: titleFont, textColor: textColor)) + string.append(NSAttributedString(string: firstName, font: item.sortOrder == .firstLast ? titleBoldFont : titleFont, textColor: textColor)) string.append(NSAttributedString(string: " ", font: titleFont, textColor: textColor)) - string.append(NSAttributedString(string: lastName, font: titleBoldFont, textColor: textColor)) + string.append(NSAttributedString(string: lastName, font: item.sortOrder == .firstLast ? titleFont : titleBoldFont, textColor: textColor)) titleAttributedString = string } else if let firstName = user.firstName, !firstName.isEmpty { titleAttributedString = NSAttributedString(string: firstName, font: titleBoldFont, textColor: textColor) @@ -769,8 +773,8 @@ class ContactsPeerItemNode: ItemListRevealOptionsItemNode { override func revealOptionsInteractivelyOpened() { if let item = self.item { switch item.peer { - case let .peer(peer, _): - if let peer = peer { + case let .peer(peer, chatPeer): + if let peer = chatPeer ?? peer { item.setPeerIdWithRevealedOptions?(peer.id, nil) } case .deviceContact: @@ -782,8 +786,8 @@ class ContactsPeerItemNode: ItemListRevealOptionsItemNode { override func revealOptionsInteractivelyClosed() { if let item = self.item { switch item.peer { - case let .peer(peer, _): - if let peer = peer { + case let .peer(peer, chatPeer): + if let peer = chatPeer ?? peer { item.setPeerIdWithRevealedOptions?(nil, peer.id) } case .deviceContact: @@ -795,8 +799,8 @@ class ContactsPeerItemNode: ItemListRevealOptionsItemNode { override func revealOptionSelected(_ option: ItemListRevealOption, animated: Bool) { if let item = self.item { switch item.peer { - case let .peer(peer, _): - if let peer = peer { + case let .peer(peer, chatPeer): + if let peer = chatPeer ?? peer { item.deletePeer?(peer.id) } case .deviceContact: diff --git a/TelegramUI/ContactsSearchContainerNode.swift b/TelegramUI/ContactsSearchContainerNode.swift index a031fa7613..1323757d22 100644 --- a/TelegramUI/ContactsSearchContainerNode.swift +++ b/TelegramUI/ContactsSearchContainerNode.swift @@ -41,7 +41,7 @@ private struct ContactListSearchEntry: Identifiable, Comparable { return lhs.index < rhs.index } - func item(account: Account, theme: PresentationTheme, strings: PresentationStrings, openPeer: @escaping (ContactListPeer) -> Void) -> ListViewItem { + func item(account: Account, theme: PresentationTheme, strings: PresentationStrings, nameSortOrder: PresentationPersonNameOrder, nameDisplayOrder: PresentationPersonNameOrder, openPeer: @escaping (ContactListPeer) -> Void) -> ListViewItem { let header: ListViewItemHeader let status: ContactsPeerItemStatus switch self.group { @@ -50,7 +50,7 @@ private struct ContactListSearchEntry: Identifiable, Comparable { status = .none case .global: header = ChatListSearchItemHeader(type: .globalPeers, theme: theme, strings: strings, actionTitle: nil, action: nil) - if case let .peer(peer, _) = self.peer, let addressName = peer.addressName { + if case let .peer(peer, _) = self.peer, let _ = peer.addressName { status = .addressName("") } else { status = .none @@ -67,7 +67,7 @@ private struct ContactListSearchEntry: Identifiable, Comparable { case let .deviceContact(stableId, contact): peerItem = .deviceContact(stableId: stableId, contact: contact) } - return ContactsPeerItem(theme: theme, strings: strings, account: account, peerMode: .peer, peer: peerItem, status: status, enabled: self.enabled, selection: .none, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), index: nil, header: header, action: { _ in + return ContactsPeerItem(theme: theme, strings: strings, sortOrder: nameSortOrder, displayOrder: nameDisplayOrder, account: account, peerMode: .peer, peer: peerItem, status: status, enabled: self.enabled, selection: .none, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), index: nil, header: header, action: { _ in openPeer(peer) }) } @@ -80,12 +80,12 @@ struct ContactListSearchContainerTransition { let isSearching: Bool } -private func contactListSearchContainerPreparedRecentTransition(from fromEntries: [ContactListSearchEntry], to toEntries: [ContactListSearchEntry], isSearching: Bool, account: Account, theme: PresentationTheme, strings: PresentationStrings, openPeer: @escaping (ContactListPeer) -> Void) -> ContactListSearchContainerTransition { +private func contactListSearchContainerPreparedRecentTransition(from fromEntries: [ContactListSearchEntry], to toEntries: [ContactListSearchEntry], isSearching: Bool, account: Account, theme: PresentationTheme, strings: PresentationStrings, nameSortOrder: PresentationPersonNameOrder, nameDisplayOrder: PresentationPersonNameOrder, openPeer: @escaping (ContactListPeer) -> Void) -> ContactListSearchContainerTransition { let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromEntries, rightList: toEntries) let deletions = deleteIndices.map { ListViewDeleteItem(index: $0, directionHint: nil) } - let insertions = indicesAndItems.map { ListViewInsertItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(account: account, theme: theme, strings: strings, openPeer: openPeer), directionHint: nil) } - let updates = updateIndices.map { ListViewUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(account: account, theme: theme, strings: strings, openPeer: openPeer), directionHint: nil) } + let insertions = indicesAndItems.map { ListViewInsertItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(account: account, theme: theme, strings: strings, nameSortOrder: nameSortOrder, nameDisplayOrder: nameDisplayOrder, openPeer: openPeer), directionHint: nil) } + let updates = updateIndices.map { ListViewUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(account: account, theme: theme, strings: strings, nameSortOrder: nameSortOrder, nameDisplayOrder: nameDisplayOrder, openPeer: openPeer), directionHint: nil) } return ContactListSearchContainerTransition(deletions: deletions, insertions: insertions, updates: updates, isSearching: isSearching) } @@ -176,12 +176,12 @@ final class ContactsSearchContainerNode: SearchDisplayControllerContentNode { var disabledPeerIds = Set() for filter in filters { switch filter { - case .excludeSelf: - existingPeerIds.insert(account.peerId) - case let .exclude(peerIds): - existingPeerIds = existingPeerIds.union(peerIds) - case let .disable(peerIds): - disabledPeerIds = disabledPeerIds.union(peerIds) + case .excludeSelf: + existingPeerIds.insert(account.peerId) + case let .exclude(peerIds): + existingPeerIds = existingPeerIds.union(peerIds) + case let .disable(peerIds): + disabledPeerIds = disabledPeerIds.union(peerIds) } } var existingNormalizedPhoneNumbers = Set() @@ -222,6 +222,9 @@ final class ContactsSearchContainerNode: SearchDisplayControllerContentNode { } } for peer in remotePeers.1 { + if !(peer.peer is TelegramUser) { + continue + } if !existingPeerIds.contains(peer.peer.id) { existingPeerIds.insert(peer.peer.id) @@ -264,25 +267,10 @@ final class ContactsSearchContainerNode: SearchDisplayControllerContentNode { if let strongSelf = self { let previousItems = previousSearchItems.swap(items ?? []) - let transition = contactListSearchContainerPreparedRecentTransition(from: previousItems, to: items ?? [], isSearching: items != nil, account: account, theme: strongSelf.presentationData.theme, strings: strongSelf.presentationData.strings, openPeer: { peer in self?.listNode.clearHighlightAnimated(true) + let transition = contactListSearchContainerPreparedRecentTransition(from: previousItems, to: items ?? [], isSearching: items != nil, account: account, theme: strongSelf.presentationData.theme, strings: strongSelf.presentationData.strings, nameSortOrder: strongSelf.presentationData.nameSortOrder, nameDisplayOrder: strongSelf.presentationData.nameDisplayOrder, openPeer: { peer in self?.listNode.clearHighlightAnimated(true) self?.openPeer(peer) }) - /*var listItems: [ListViewItem] = [] - for item in items { - switch item { - case let .peer(peer, theme, strings): - - - listItems.append(ContactsPeerItem(theme: theme, strings: strings, account: account, peerMode: .peer, peer: peer, chatPeer: peer, status: .none, enabled: enabled, selection: .none, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), index: nil, header: nil, action: { [weak self] _ in - if let openPeer = self?.openPeer { - self?.listNode.clearHighlightAnimated(true) - openPeer(peer.id) - } - })) - } - }*/ - strongSelf.enqueueTransition(transition) } })) diff --git a/TelegramUI/CreatePasswordController.swift b/TelegramUI/CreatePasswordController.swift index bdb9159d01..8eb4e39c80 100644 --- a/TelegramUI/CreatePasswordController.swift +++ b/TelegramUI/CreatePasswordController.swift @@ -13,9 +13,11 @@ private enum CreatePasswordField { private final class CreatePasswordControllerArguments { let updateFieldText: (CreatePasswordField, String) -> Void + let cancelEmailConfirmation: () -> Void - init(updateFieldText: @escaping (CreatePasswordField, String) -> Void) { + init(updateFieldText: @escaping (CreatePasswordField, String) -> Void, cancelEmailConfirmation: @escaping () -> Void) { self.updateFieldText = updateFieldText + self.cancelEmailConfirmation = cancelEmailConfirmation } } @@ -23,6 +25,7 @@ private enum CreatePasswordSection: Int32 { case password case hint case email + case emailCancel } private enum CreatePasswordEntryTag: ItemListItemTag { @@ -54,14 +57,19 @@ private enum CreatePasswordEntry: ItemListNodeEntry, Equatable { case email(PresentationTheme, String, String) case emailInfo(PresentationTheme, String) + case emailConfirmation(PresentationTheme, String) + case emailCancel(PresentationTheme, String, Bool) + var section: ItemListSectionId { switch self { case .passwordHeader, .password, .passwordConfirmation, .passwordInfo: return CreatePasswordSection.password.rawValue case .hintHeader, .hint, .hintInfo: return CreatePasswordSection.hint.rawValue - case .emailHeader, .email, .emailInfo: + case .emailHeader, .email, .emailInfo, .emailConfirmation: return CreatePasswordSection.email.rawValue + case .emailCancel: + return CreatePasswordSection.emailCancel.rawValue } } @@ -89,6 +97,10 @@ private enum CreatePasswordEntry: ItemListNodeEntry, Equatable { return 8 case .emailInfo: return 9 + case .emailConfirmation: + return 10 + case .emailCancel: + return 11 } } @@ -115,8 +127,8 @@ private enum CreatePasswordEntry: ItemListNodeEntry, Equatable { case let .hintHeader(theme, text): return ItemListSectionHeaderItem(theme: theme, text: text, sectionId: self.section) case let .hint(theme, text, value): - return ItemListSingleLineInputItem(theme: theme, title: NSAttributedString(), text: value, placeholder: text, type: .regular(capitalization: true, autocorrection: false), spacing: 0.0, tag: CreatePasswordEntryTag.password, sectionId: self.section, textUpdated: { updatedText in - arguments.updateFieldText(.password, updatedText) + return ItemListSingleLineInputItem(theme: theme, title: NSAttributedString(), text: value, placeholder: text, type: .regular(capitalization: true, autocorrection: false), spacing: 0.0, tag: CreatePasswordEntryTag.hint, sectionId: self.section, textUpdated: { updatedText in + arguments.updateFieldText(.hint, updatedText) }, action: { }) case let .hintInfo(theme, text): @@ -124,51 +136,75 @@ private enum CreatePasswordEntry: ItemListNodeEntry, Equatable { case let .emailHeader(theme, text): return ItemListSectionHeaderItem(theme: theme, text: text, sectionId: self.section) case let .email(theme, text, value): - return ItemListSingleLineInputItem(theme: theme, title: NSAttributedString(), text: value, placeholder: text, type: .email, spacing: 0.0, tag: CreatePasswordEntryTag.password, sectionId: self.section, textUpdated: { updatedText in - arguments.updateFieldText(.password, updatedText) + return ItemListSingleLineInputItem(theme: theme, title: NSAttributedString(), text: value, placeholder: text, type: .email, spacing: 0.0, tag: CreatePasswordEntryTag.email, sectionId: self.section, textUpdated: { updatedText in + arguments.updateFieldText(.email, updatedText) }, action: { }) case let .emailInfo(theme, text): return ItemListTextItem(theme: theme, text: .plain(text), sectionId: self.section) + case let .emailConfirmation(theme, text): + return ItemListTextItem(theme: theme, text: .plain(text), sectionId: self.section) + case let .emailCancel(theme, text, enabled): + return ItemListActionItem(theme: theme, title: text, kind: enabled ? .generic : .disabled, alignment: .natural, sectionId: self.section, style: .blocks, action: { + arguments.cancelEmailConfirmation() + }) } } } private struct CreatePasswordControllerState: Equatable { + var state: CreatePasswordState var passwordText: String = "" var passwordConfirmationText: String = "" var hintText: String = "" var emailText: String = "" var saving: Bool = false - var pendingEmail: String? = nil + + init(state: CreatePasswordState) { + self.state = state + } } private func createPasswordControllerEntries(presentationData: PresentationData, state: CreatePasswordControllerState) -> [CreatePasswordEntry] { var entries: [CreatePasswordEntry] = [] - entries.append(.passwordHeader(presentationData.theme, presentationData.strings.FastTwoStepSetup_PasswordSection)) - entries.append(.password(presentationData.theme, presentationData.strings.FastTwoStepSetup_PasswordPlaceholder, state.passwordText)) - entries.append(.passwordConfirmation(presentationData.theme, presentationData.strings.FastTwoStepSetup_PasswordConfirmationPlaceholder, state.passwordConfirmationText)) - entries.append(.passwordInfo(presentationData.theme, presentationData.strings.FastTwoStepSetup_PasswordHelp)) - - entries.append(.hintHeader(presentationData.theme, presentationData.strings.FastTwoStepSetup_HintSection)) - entries.append(.hint(presentationData.theme, presentationData.strings.FastTwoStepSetup_HintPlaceholder, state.hintText)) - entries.append(.hintInfo(presentationData.theme, presentationData.strings.FastTwoStepSetup_HintHelp)) - - entries.append(.emailHeader(presentationData.theme, presentationData.strings.FastTwoStepSetup_EmailSection)) - entries.append(.email(presentationData.theme, presentationData.strings.FastTwoStepSetup_EmailPlaceholder, state.emailText)) - entries.append(.emailInfo(presentationData.theme, presentationData.strings.FastTwoStepSetup_EmailHelp)) + switch state.state { + case let .setup(currentPassword): + entries.append(.passwordHeader(presentationData.theme, presentationData.strings.FastTwoStepSetup_PasswordSection)) + entries.append(.password(presentationData.theme, presentationData.strings.FastTwoStepSetup_PasswordPlaceholder, state.passwordText)) + entries.append(.passwordConfirmation(presentationData.theme, presentationData.strings.FastTwoStepSetup_PasswordConfirmationPlaceholder, state.passwordConfirmationText)) + entries.append(.passwordInfo(presentationData.theme, presentationData.strings.FastTwoStepSetup_PasswordHelp)) + + entries.append(.hintHeader(presentationData.theme, presentationData.strings.FastTwoStepSetup_HintSection)) + entries.append(.hint(presentationData.theme, presentationData.strings.FastTwoStepSetup_HintPlaceholder, state.hintText)) + entries.append(.hintInfo(presentationData.theme, presentationData.strings.FastTwoStepSetup_HintHelp)) + + if currentPassword == nil { + entries.append(.emailHeader(presentationData.theme, presentationData.strings.FastTwoStepSetup_EmailSection)) + entries.append(.email(presentationData.theme, presentationData.strings.FastTwoStepSetup_EmailPlaceholder, state.emailText)) + entries.append(.emailInfo(presentationData.theme, presentationData.strings.FastTwoStepSetup_EmailHelp)) + } + case let .pendingVerification(emailPattern): + entries.append(.emailConfirmation(presentationData.theme, presentationData.strings.TwoStepAuth_ConfirmationText + "\n\(emailPattern)")) + entries.append(.emailCancel(presentationData.theme, presentationData.strings.TwoStepAuth_ConfirmationAbort, !state.saving)) + } return entries } -func createPasswordController(account: Account, completion: @escaping (String, String) -> Void) -> ViewController { - let statePromise = ValuePromise(CreatePasswordControllerState(), ignoreRepeated: true) - let stateValue = Atomic(value: CreatePasswordControllerState()) +enum CreatePasswordState: Equatable { + case setup(currentPassword: String?) + case pendingVerification(emailPattern: String) +} + +func createPasswordController(account: Account, state: CreatePasswordState, completion: @escaping (String, String, Bool) -> Void, updatePasswordEmailConfirmation: @escaping (String?) -> Void, processPasswordEmailConfirmation: Bool = true) -> ViewController { + let statePromise = ValuePromise(CreatePasswordControllerState(state: state), ignoreRepeated: true) + let stateValue = Atomic(value: CreatePasswordControllerState(state: state)) let updateState: ((CreatePasswordControllerState) -> CreatePasswordControllerState) -> Void = { f in statePromise.set(stateValue.modify { f($0) }) } + var dismissImpl: (() -> Void)? var presentControllerImpl: ((ViewController, ViewControllerPresentationArguments?) -> Void)? let actionsDisposable = DisposableSet() @@ -191,6 +227,36 @@ func createPasswordController(account: Account, completion: @escaping (String, S } return state } + }, cancelEmailConfirmation: { + var currentPassword: String? + updateState { state in + var state = state + switch state.state { + case let .setup(password): + currentPassword = password + case .pendingVerification: + currentPassword = nil + } + state.saving = true + return state + } + + saveDisposable.set((updateTwoStepVerificationPassword(network: account.network, currentPassword: currentPassword, updatedPassword: .none) + |> deliverOnMainQueue).start(next: { _ in + updateState { state in + var state = state + state.saving = false + state.state = .setup(currentPassword: nil) + return state + } + updatePasswordEmailConfirmation(nil) + }, error: { _ in + updateState { state in + var state = state + state.saving = false + return state + } + })) }) var initialFocusImpl: (() -> Void)? @@ -199,63 +265,109 @@ func createPasswordController(account: Account, completion: @escaping (String, S |> deliverOnMainQueue |> map { presentationData, state -> (ItemListControllerState, (ItemListNodeState, CreatePasswordEntry.ItemGenerationArguments)) in + let leftNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Common_Cancel), style: .regular, enabled: true, action: { + dismissImpl?() + }) var rightNavigationButton: ItemListNavigationButton? if state.saving { rightNavigationButton = ItemListNavigationButton(content: .none, style: .activity, enabled: true, action: {}) } else { - rightNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Common_Done), style: .bold, enabled: !state.passwordText.isEmpty, action: { - var state: CreatePasswordControllerState? - updateState { s in - state = s - return s - } - if let state = state { - if state.passwordText.isEmpty { - } else if state.passwordText != state.passwordConfirmationText { - let presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 } - presentControllerImpl?(standardTextAlertController(theme: AlertControllerTheme(presentationTheme: presentationData.theme), title: nil, text: presentationData.strings.TwoStepAuth_SetupPasswordConfirmFailed, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), nil) - } else { - let saveImpl: () -> Void = { - updateState { state in - var state = state - state.saving = true - return state - } - saveDisposable.set((updateTwoStepVerificationPassword(network: account.network, currentPassword: nil, updatedPassword: .password(password: state.passwordText, hint: state.hintText, email: state.emailText)) - |> deliverOnMainQueue).start(next: { update in - switch update { - case .none: - break - case let .password(password, pendingEmailPattern): - if let pendingEmailPattern = pendingEmailPattern { - updateState { state in - var state = state - state.saving = false - state.pendingEmail = pendingEmailPattern - return state + switch state.state { + case .setup: + rightNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Common_Done), style: .bold, enabled: !state.passwordText.isEmpty, action: { + var state: CreatePasswordControllerState? + updateState { s in + state = s + return s + } + if let state = state { + if state.passwordText.isEmpty { + } else if state.passwordText != state.passwordConfirmationText { + let presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 } + presentControllerImpl?(standardTextAlertController(theme: AlertControllerTheme(presentationTheme: presentationData.theme), title: nil, text: presentationData.strings.TwoStepAuth_SetupPasswordConfirmFailed, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), nil) + } else { + let saveImpl: () -> Void = { + var currentPassword: String? + var email: String? + updateState { state in + var state = state + if case let .setup(password) = state.state { + currentPassword = password + if password != nil { + email = nil + } else { + email = state.emailText } - } else { - completion(password, state.hintText) } + state.saving = true + return state + } + saveDisposable.set((updateTwoStepVerificationPassword(network: account.network, currentPassword: currentPassword, updatedPassword: .password(password: state.passwordText, hint: state.hintText, email: email)) + |> deliverOnMainQueue).start(next: { update in + switch update { + case .none: + break + case let .password(password, pendingEmailPattern): + if let pendingEmailPattern = pendingEmailPattern { + if processPasswordEmailConfirmation { + updateState { state in + var state = state + state.saving = false + state.state = .pendingVerification(emailPattern: pendingEmailPattern) + + return state + } + } + updatePasswordEmailConfirmation(pendingEmailPattern) + } else { + completion(password, state.hintText, !state.emailText.isEmpty) + } + } + }, error: { _ in + presentControllerImpl?(standardTextAlertController(theme: AlertControllerTheme(presentationTheme: presentationData.theme), title: nil, text: presentationData.strings.Login_UnknownError, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), nil) + })) } - }, error: { _ in - presentControllerImpl?(standardTextAlertController(theme: AlertControllerTheme(presentationTheme: presentationData.theme), title: nil, text: presentationData.strings.Login_UnknownError, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), nil) - })) + + var emailAlert = false + switch state.state { + case let .setup(currentPassword): + if currentPassword != nil { + emailAlert = false + } else { + emailAlert = state.emailText.isEmpty + } + case .pendingVerification: + break + } + + if emailAlert { + presentControllerImpl?(standardTextAlertController(theme: AlertControllerTheme(presentationTheme: presentationData.theme), title: nil, text: presentationData.strings.TwoStepAuth_EmailSkipAlert, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .destructiveAction, title: presentationData.strings.TwoStepAuth_EmailSkip, action: { + saveImpl() + })]), nil) + } else { + saveImpl() + } + } } - - if state.emailText.isEmpty { - presentControllerImpl?(standardTextAlertController(theme: AlertControllerTheme(presentationTheme: presentationData.theme), title: nil, text: presentationData.strings.TwoStepAuth_EmailSkipAlert, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .destructiveAction, title: presentationData.strings.TwoStepAuth_EmailSkip, action: { - saveImpl() - })]), nil) - } else { - saveImpl() - } - } - } - }) + }) + case .pendingVerification: + break + } } - let controllerState = ItemListControllerState(theme: presentationData.theme, title: .text(presentationData.strings.FastTwoStepSetup_Title), leftNavigationButton: nil, rightNavigationButton: rightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: false) + let title: String + switch state.state { + case let .setup(currentPassword): + if currentPassword != nil { + title = presentationData.strings.TwoStepAuth_ChangePassword + } else { + title = presentationData.strings.FastTwoStepSetup_Title + } + case .pendingVerification: + title = presentationData.strings.FastTwoStepSetup_Title + } + + let controllerState = ItemListControllerState(theme: presentationData.theme, title: .text(title), leftNavigationButton: leftNavigationButton, rightNavigationButton: rightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: false) let listState = ItemListNodeState(entries: createPasswordControllerEntries(presentationData: presentationData, state: state), style: .blocks, focusItemTag: CreatePasswordEntryTag.password, emptyStateItem: nil, animateChanges: false) return (controllerState, (listState, arguments)) @@ -265,6 +377,10 @@ func createPasswordController(account: Account, completion: @escaping (String, S } let controller = ItemListController(account: account, state: signal) + dismissImpl = { [weak controller] in + controller?.view.endEditing(true) + controller?.dismiss() + } presentControllerImpl = { [weak controller] c, p in if let controller = controller { controller.present(c, in: .window(.root), with: p) @@ -286,7 +402,10 @@ func createPasswordController(account: Account, completion: @escaping (String, S resultItemNode.focus() } } - controller.didAppear = { + controller.didAppear = { firstTime in + if !firstTime { + return + } initialFocusImpl?() } diff --git a/TelegramUI/DefaultDarkAccentPresentationTheme.swift b/TelegramUI/DefaultDarkAccentPresentationTheme.swift index efdd0aac41..772e0b4a5f 100644 --- a/TelegramUI/DefaultDarkAccentPresentationTheme.swift +++ b/TelegramUI/DefaultDarkAccentPresentationTheme.swift @@ -97,7 +97,8 @@ private let list = PresentationThemeList( freeInputField: PresentationInputFieldTheme( backgroundColor: UIColor(rgb: 0xDBF5FF, alpha: 0.5), placeholderColor: UIColor(rgb: 0x4d4d4d), - primaryColor: .white + primaryColor: .white, + controlColor: UIColor(rgb: 0x4d4d4d) ) ) diff --git a/TelegramUI/DefaultDarkPresentationTheme.swift b/TelegramUI/DefaultDarkPresentationTheme.swift index 010f62b71b..d8d7432634 100644 --- a/TelegramUI/DefaultDarkPresentationTheme.swift +++ b/TelegramUI/DefaultDarkPresentationTheme.swift @@ -97,7 +97,8 @@ private let list = PresentationThemeList( freeInputField: PresentationInputFieldTheme( backgroundColor: UIColor(rgb: 0xffffff, alpha: 0.5), placeholderColor: UIColor(rgb: 0x4d4d4d), - primaryColor: .white + primaryColor: .white, + controlColor: UIColor(rgb: 0x4d4d4d) ) ) diff --git a/TelegramUI/DefaultPresentationTheme.swift b/TelegramUI/DefaultPresentationTheme.swift index d85cccf641..b2b6c3f1cb 100644 --- a/TelegramUI/DefaultPresentationTheme.swift +++ b/TelegramUI/DefaultPresentationTheme.swift @@ -97,7 +97,8 @@ private func makeDefaultPresentationTheme(accentColor: UIColor, day: Bool) -> Pr freeInputField: PresentationInputFieldTheme( backgroundColor: UIColor(rgb: 0xd6d6dc), placeholderColor: UIColor(rgb: 0x96979d), - primaryColor: .black + primaryColor: .black, + controlColor: UIColor(rgb: 0x96979d) ) ) diff --git a/TelegramUI/GalleryController.swift b/TelegramUI/GalleryController.swift index 60c1b2088f..d87724b6c6 100644 --- a/TelegramUI/GalleryController.swift +++ b/TelegramUI/GalleryController.swift @@ -94,13 +94,18 @@ private let internalMimeTypes = Set([ "application/text" ]) -private var intermalMimePrefixes: [String] = [ +private let internalMimePrefixes: [String] = [ "image/", "text/", - "application/vnd.ms-", - "video/" + "application/vnd.ms-" ] +private let supportedVideoMimeTypes = Set([ + "video/mp4", + "video/mpeg4", + "video/mov" +]) + func internalDocumentItemSupportsMimeType(_ type: String, fileName: String?) -> Bool { if let fileName = fileName { let ext = (fileName as NSString).pathExtension @@ -112,7 +117,10 @@ func internalDocumentItemSupportsMimeType(_ type: String, fileName: String?) -> if internalMimeTypes.contains(type) { return true } - for prefix in intermalMimePrefixes { + if supportedVideoMimeTypes.contains(type) { + return true + } + for prefix in internalMimePrefixes { if type.hasPrefix(prefix) { return true } @@ -127,7 +135,7 @@ func galleryItemForEntry(account: Account, theme: PresentationTheme, strings: Pr if let _ = media as? TelegramMediaImage { return ChatImageGalleryItem(account: account, theme: theme, strings: strings, message: message, location: location) } else if let file = media as? TelegramMediaFile { - if file.isVideo || file.mimeType.hasPrefix("video/") { + if file.isVideo || supportedVideoMimeTypes.contains(file.mimeType) { let content: UniversalVideoContent if file.isAnimated { content = NativeVideoContent(id: .message(message.id, message.stableId + 1, file.fileId), fileReference: .message(message: MessageReference(message), media: file), streamVideo: streamVideos, loopVideo: true) diff --git a/TelegramUI/GroupInfoController.swift b/TelegramUI/GroupInfoController.swift index 1c77ff3528..47d66e5a54 100644 --- a/TelegramUI/GroupInfoController.swift +++ b/TelegramUI/GroupInfoController.swift @@ -719,6 +719,8 @@ private func groupInfoEntries(account: Account, presentationData: PresentationDa } if channel.hasAdminRights(.canInviteUsers) { canAddMembers = true + } else if case let .group(info) = channel.info, info.flags.contains(.everyMemberCanInviteMembers) { + canAddMembers = true } } diff --git a/TelegramUI/GroupInfoSearchItem.swift b/TelegramUI/GroupInfoSearchItem.swift index 164ec05504..99b3df5c34 100644 --- a/TelegramUI/GroupInfoSearchItem.swift +++ b/TelegramUI/GroupInfoSearchItem.swift @@ -11,12 +11,28 @@ final class ChannelMembersSearchItem: ItemListControllerSearch { let cancel: () -> Void let openPeer: (Peer, RenderedChannelParticipant?) -> Void let searchMode: ChannelMembersSearchMode + private var updateActivity: ((Bool) -> Void)? + private var activity: ValuePromise = ValuePromise(ignoreRepeated: false) + private let activityDisposable = MetaDisposable() init(account: Account, peerId: PeerId, searchMode: ChannelMembersSearchMode = .searchMembers, cancel: @escaping () -> Void, openPeer: @escaping (Peer, RenderedChannelParticipant?) -> Void) { self.account = account self.peerId = peerId self.cancel = cancel self.openPeer = openPeer self.searchMode = searchMode + activityDisposable.set((activity.get() |> mapToSignal { value -> Signal in + if value { + return .single(value) |> delay(0.2, queue: Queue.mainQueue()) + } else { + return .single(value) + } + }).start(next: { [weak self] value in + self?.updateActivity?(value) + })) + } + + deinit { + activityDisposable.dispose() } func isEqual(to: ItemListControllerSearch) -> Bool { @@ -38,22 +54,26 @@ final class ChannelMembersSearchItem: ItemListControllerSearch { return current } else { let presentationData = self.account.telegramApplicationContext.currentPresentationData.with { $0 } - return GroupInfoSearchNavigationContentNode(theme: presentationData.theme, strings: presentationData.strings, cancel: self.cancel) + return GroupInfoSearchNavigationContentNode(theme: presentationData.theme, strings: presentationData.strings, cancel: self.cancel, updateActivity: { [weak self] value in + self?.updateActivity = value + }) } } func node(current: ItemListControllerSearchNode?) -> ItemListControllerSearchNode { - return ChannelMembersSearchItemNode(account: self.account, peerId: self.peerId, searchMode: self.searchMode, openPeer: self.openPeer, cancel: self.cancel) + return ChannelMembersSearchItemNode(account: self.account, peerId: self.peerId, searchMode: self.searchMode, openPeer: self.openPeer, cancel: self.cancel, updateActivity: { [weak self] value in + self?.activity.set(value) + }) } } private final class ChannelMembersSearchItemNode: ItemListControllerSearchNode { private let containerNode: ChannelMembersSearchContainerNode - init(account: Account, peerId: PeerId, searchMode: ChannelMembersSearchMode, openPeer: @escaping (Peer, RenderedChannelParticipant?) -> Void, cancel: @escaping () -> Void) { + init(account: Account, peerId: PeerId, searchMode: ChannelMembersSearchMode, openPeer: @escaping (Peer, RenderedChannelParticipant?) -> Void, cancel: @escaping () -> Void, updateActivity: @escaping(Bool)->Void) { self.containerNode = ChannelMembersSearchContainerNode(account: account, peerId: peerId, mode: searchMode, filters: [], openPeer: { peer, participant in openPeer(peer, participant) - }) + }, updateActivity: updateActivity) self.containerNode.cancel = { cancel() } diff --git a/TelegramUI/GroupInfoSearchNavigationContentNode.swift b/TelegramUI/GroupInfoSearchNavigationContentNode.swift index 060ec77aee..7938b3bc4e 100644 --- a/TelegramUI/GroupInfoSearchNavigationContentNode.swift +++ b/TelegramUI/GroupInfoSearchNavigationContentNode.swift @@ -14,9 +14,14 @@ final class GroupInfoSearchNavigationContentNode: NavigationBarContentNode, Item private let searchBar: SearchBarNode - private var queryUpdated: ((String) -> Void)? - init(theme: PresentationTheme, strings: PresentationStrings, cancel: @escaping () -> Void) { + private var queryUpdated: ((String) -> Void)? + var activity: Bool = false { + didSet { + searchBar.activity = activity + } + } + init(theme: PresentationTheme, strings: PresentationStrings, cancel: @escaping () -> Void, updateActivity: @escaping(@escaping(Bool)->Void) -> Void) { self.theme = theme self.strings = strings @@ -38,6 +43,10 @@ final class GroupInfoSearchNavigationContentNode: NavigationBarContentNode, Item self.searchBar.textUpdated = { [weak self] query in self?.queryUpdated?(query) } + + updateActivity({ [weak self] value in + self?.activity = value + }) } func setQueryUpdated(_ f: @escaping (String) -> Void) { diff --git a/TelegramUI/HashtagSearchController.swift b/TelegramUI/HashtagSearchController.swift index c9ca216d94..989e8d0a29 100644 --- a/TelegramUI/HashtagSearchController.swift +++ b/TelegramUI/HashtagSearchController.swift @@ -33,7 +33,7 @@ final class HashtagSearchController: TelegramController { self.title = query self.navigationItem.backBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Back, style: .plain, target: nil, action: nil) - let chatListPresentationData = ChatListPresentationData(theme: self.presentationData.theme, strings: self.presentationData.strings, timeFormat: self.presentationData.timeFormat) + let chatListPresentationData = ChatListPresentationData(theme: self.presentationData.theme, strings: self.presentationData.strings, timeFormat: self.presentationData.timeFormat, nameSortOrder: self.presentationData.nameSortOrder, nameDisplayOrder: self.presentationData.nameDisplayOrder) let location: SearchMessagesLocation = .general let search = searchMessages(account: account, location: location, query: query) diff --git a/TelegramUI/InstalledStickerPacksController.swift b/TelegramUI/InstalledStickerPacksController.swift index 8e1d4145d3..742abc05a4 100644 --- a/TelegramUI/InstalledStickerPacksController.swift +++ b/TelegramUI/InstalledStickerPacksController.swift @@ -422,7 +422,19 @@ public func installedStickerPacksController(account: Account, mode: InstalledSti ActionSheetTextItem(title: presentationData.strings.StickerSettings_ContextInfo), ActionSheetButtonItem(title: presentationData.strings.StickerSettings_ContextHide, color: .accent, action: { dismissAction() + archivedPromise.set(archivedStickerPacks(account: account) |> map {Optional($0)} |> afterNext { packs in + updatedPacks(packs) + }) +// let archivedSignal = archivedPromise.get() |> take(1) |> map { packs -> [ArchivedStickerPackItem]? in +// return packs?.filter({$0.info.id != id}) +// } +// _ = archivedSignal.start(next: { packs in +// archivedPromise.set(.single(packs)) +// updatedPacks(packs) +// }) + let _ = removeStickerPackInteractively(postbox: account.postbox, id: id, option: .archive).start() + }), ActionSheetButtonItem(title: presentationData.strings.Common_Delete, color: .destructive, action: { dismissAction() diff --git a/TelegramUI/InstantPageLayout.swift b/TelegramUI/InstantPageLayout.swift index 05ac5ee745..c718d07ca0 100644 --- a/TelegramUI/InstantPageLayout.swift +++ b/TelegramUI/InstantPageLayout.swift @@ -274,7 +274,7 @@ func layoutInstantPageBlock(webpage: TelegramMediaWebpage, block: InstantPageBlo var contentSize = CGSize(width: boundingWidth - safeInset * 2.0, height: 0.0) var items: [InstantPageItem] = [] - let mediaItem = InstantPageImageItem(frame: CGRect(origin: CGPoint(x: floor((boundingWidth - safeInset * 2.0 - filledSize.width) / 2.0), y: 0.0), size: filledSize), webPage: webpage, media: InstantPageMedia(index: mediaIndex, media: image, caption: caption.plainText), interactive: true, roundCorners: false, fit: false) + let mediaItem = InstantPageImageItem(frame: CGRect(origin: CGPoint(x: floor((boundingWidth - filledSize.width) / 2.0), y: 0.0), size: filledSize), webPage: webpage, media: InstantPageMedia(index: mediaIndex, media: image, caption: caption.plainText), interactive: true, roundCorners: false, fit: false) items.append(mediaItem) contentSize.height += filledSize.height @@ -319,11 +319,11 @@ func layoutInstantPageBlock(webpage: TelegramMediaWebpage, block: InstantPageBlo var items: [InstantPageItem] = [] if autoplay { - let mediaItem = InstantPagePlayableVideoItem(frame: CGRect(origin: CGPoint(x: floor((boundingWidth - safeInset * 2.0 - filledSize.width) / 2.0), y: 0.0), size: filledSize), webPage: webpage, media: InstantPageMedia(index: mediaIndex, media: file, caption: caption.plainText), interactive: true) + let mediaItem = InstantPagePlayableVideoItem(frame: CGRect(origin: CGPoint(x: floor((boundingWidth - filledSize.width) / 2.0), y: 0.0), size: filledSize), webPage: webpage, media: InstantPageMedia(index: mediaIndex, media: file, caption: caption.plainText), interactive: true) items.append(mediaItem) } else { - let mediaItem = InstantPageImageItem(frame: CGRect(origin: CGPoint(x: floor((boundingWidth - safeInset * 2.0 - filledSize.width) / 2.0), y: 0.0), size: filledSize), webPage: webpage, media: InstantPageMedia(index: mediaIndex, media: file, caption: caption.plainText), interactive: true, roundCorners: false, fit: false) + let mediaItem = InstantPageImageItem(frame: CGRect(origin: CGPoint(x: floor((boundingWidth - filledSize.width) / 2.0), y: 0.0), size: filledSize), webPage: webpage, media: InstantPageMedia(index: mediaIndex, media: file, caption: caption.plainText), interactive: true, roundCorners: false, fit: false) items.append(mediaItem) } diff --git a/TelegramUI/InstantPageLayoutSpacings.swift b/TelegramUI/InstantPageLayoutSpacings.swift index fcf047d89b..6d1271feca 100644 --- a/TelegramUI/InstantPageLayoutSpacings.swift +++ b/TelegramUI/InstantPageLayoutSpacings.swift @@ -12,8 +12,8 @@ func spacingBetweenBlocks(upper: InstantPageBlock?, lower: InstantPageBlock?) -> return 27.0 case (_, .title): return 20.0 - case (.title, .authorDate): - return 26.0 + case (.title, .authorDate), (.subtitle, .authorDate): + return 18.0 case (_, .authorDate): return 20.0 case (.title, .paragraph), (.authorDate, .paragraph): @@ -24,6 +24,8 @@ func spacingBetweenBlocks(upper: InstantPageBlock?, lower: InstantPageBlock?) -> return 31.0 case (.preformatted, .paragraph): return 19.0 + case (.paragraph, .paragraph): + return 25.0 case (_, .paragraph): return 20.0 case (.title, .list), (.authorDate, .list): diff --git a/TelegramUI/InviteContactsController.swift b/TelegramUI/InviteContactsController.swift index 7404dc30ad..9df17cec36 100644 --- a/TelegramUI/InviteContactsController.swift +++ b/TelegramUI/InviteContactsController.swift @@ -39,7 +39,7 @@ public class InviteContactsController: ViewController, MFMessageComposeViewContr self.scrollToTop = { [weak self] in if let strongSelf = self { - //strongSelf.contactsNode.listNode.scrollToTop() + strongSelf.contactsNode.scrollToTop() } } diff --git a/TelegramUI/InviteContactsControllerNode.swift b/TelegramUI/InviteContactsControllerNode.swift index 6ee0f2b719..225d51e43b 100644 --- a/TelegramUI/InviteContactsControllerNode.swift +++ b/TelegramUI/InviteContactsControllerNode.swift @@ -66,7 +66,7 @@ private final class InviteContactsInteraction { private enum InviteContactsEntry: Comparable, Identifiable { case search(PresentationTheme, PresentationStrings) case option(Int, ContactListAdditionalOption, PresentationTheme, PresentationStrings) - case peer(Int, DeviceContactStableId, DeviceContactBasicData, Int32, ContactsPeerItemSelection, PresentationTheme, PresentationStrings) + case peer(Int, DeviceContactStableId, DeviceContactBasicData, Int32, ContactsPeerItemSelection, PresentationTheme, PresentationStrings, PresentationPersonNameOrder, PresentationPersonNameOrder) var stableId: InviteContactsEntryId { switch self { @@ -74,7 +74,7 @@ private enum InviteContactsEntry: Comparable, Identifiable { return .search case let .option(index, _, _, _): return .option(index: index) - case let .peer(_, id, _, _, _, _, _): + case let .peer(_, id, _, _, _, _, _, _, _): return .contactId(id) } } @@ -87,7 +87,7 @@ private enum InviteContactsEntry: Comparable, Identifiable { }) case let .option(_, option, theme, _): return ContactListActionItem(theme: theme, title: option.title, icon: option.icon, action: option.action) - case let .peer(_, id, contact, count, selection, theme, strings): + case let .peer(_, id, contact, count, selection, theme, strings, nameSortOrder, nameDisplayOrder): let status: ContactsPeerItemStatus if count != 0 { status = .custom(strings.Contacts_ImportersCount(count)) @@ -95,7 +95,7 @@ private enum InviteContactsEntry: Comparable, Identifiable { status = .none } let peer = TelegramUser(id: PeerId(namespace: -1, id: 0), accessHash: nil, firstName: contact.firstName, lastName: contact.lastName, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: []) - return ContactsPeerItem(theme: theme, strings: strings, account: account, peerMode: .peer, peer: .peer(peer: peer, chatPeer: peer), status: status, enabled: true, selection: selection, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), index: nil, header: ChatListSearchItemHeader(type: .contacts, theme: theme, strings: strings, actionTitle: nil, action: nil), action: { _ in + return ContactsPeerItem(theme: theme, strings: strings, sortOrder: nameSortOrder, displayOrder: nameDisplayOrder, account: account, peerMode: .peer, peer: .peer(peer: peer, chatPeer: peer), status: status, enabled: true, selection: selection, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), index: nil, header: ChatListSearchItemHeader(type: .contacts, theme: theme, strings: strings, actionTitle: nil, action: nil), action: { _ in interaction.toggleContact(id) }) } @@ -115,9 +115,9 @@ private enum InviteContactsEntry: Comparable, Identifiable { } else { return false } - case let .peer(lhsIndex, lhsId, lhsContact, lhsCount, lhsSelection, lhsTheme, lhsStrings): + case let .peer(lhsIndex, lhsId, lhsContact, lhsCount, lhsSelection, lhsTheme, lhsStrings, lhsSortOrder, lhsDisplayOrder): switch rhs { - case let .peer(rhsIndex, rhsId, rhsContact, rhsCount, rhsSelection, rhsTheme, rhsStrings): + case let .peer(rhsIndex, rhsId, rhsContact, rhsCount, rhsSelection, rhsTheme, rhsStrings, rhsSortOrder, rhsDisplayOrder): if lhsIndex != rhsIndex { return false } @@ -139,6 +139,12 @@ private enum InviteContactsEntry: Comparable, Identifiable { if lhsStrings !== rhsStrings { return false } + if lhsSortOrder != rhsSortOrder { + return false + } + if lhsDisplayOrder != rhsDisplayOrder { + return false + } return true default: return false @@ -159,11 +165,11 @@ private enum InviteContactsEntry: Comparable, Identifiable { case .peer: return true } - case let .peer(lhsIndex, _, _, _, _, _, _): + case let .peer(lhsIndex, _, _, _, _, _, _, _, _): switch rhs { case .search, .option: return false - case let .peer(rhsIndex, _, _, _, _, _, _): + case let .peer(rhsIndex, _, _, _, _, _, _, _, _): return lhsIndex < rhsIndex } } @@ -214,7 +220,7 @@ struct InviteContactsGroupSelectionState: Equatable { } } -private func inviteContactsEntries(accountPeer: Peer?, sortedContacts: [(DeviceContactStableId, DeviceContactBasicData, Int32)], selectionState: InviteContactsGroupSelectionState, theme: PresentationTheme, strings: PresentationStrings, interaction: InviteContactsInteraction) -> [InviteContactsEntry] { +private func inviteContactsEntries(accountPeer: Peer?, sortedContacts: [(DeviceContactStableId, DeviceContactBasicData, Int32)], selectionState: InviteContactsGroupSelectionState, theme: PresentationTheme, strings: PresentationStrings, nameSortOrder: PresentationPersonNameOrder, nameDisplayOrder: PresentationPersonNameOrder, interaction: InviteContactsInteraction) -> [InviteContactsEntry] { var entries: [InviteContactsEntry] = [] entries.append(.search(theme, strings)) @@ -225,7 +231,7 @@ private func inviteContactsEntries(accountPeer: Peer?, sortedContacts: [(DeviceC var index = 0 for (id, contact, count) in sortedContacts { - entries.append(.peer(index, id, contact, count, .selectable(selected: selectionState.selectedContactIndices[id] != nil), theme, strings)) + entries.append(.peer(index, id, contact, count, .selectable(selected: selectionState.selectedContactIndices[id] != nil), theme, strings, nameSortOrder, nameDisplayOrder)) index += 1 } @@ -290,7 +296,7 @@ final class InviteContactsControllerNode: ASDisplayNode { private var presentationData: PresentationData private var presentationDataDisposable: Disposable? - private let themeAndStringsPromise: Promise<(PresentationTheme, PresentationStrings)> + private let themeAndStringsPromise: Promise<(PresentationTheme, PresentationStrings, PresentationPersonNameOrder, PresentationPersonNameOrder)> private let _ready = Promise() private var readyValue = false { @@ -313,7 +319,7 @@ final class InviteContactsControllerNode: ASDisplayNode { self.presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 } - self.themeAndStringsPromise = Promise((self.presentationData.theme, self.presentationData.strings)) + self.themeAndStringsPromise = Promise((self.presentationData.theme, self.presentationData.strings, self.presentationData.nameSortOrder, self.presentationData.nameDisplayOrder)) self.listNode = ListView() @@ -427,7 +433,7 @@ final class InviteContactsControllerNode: ASDisplayNode { transition = (combineLatest(sortedContacts, selectionStateSignal, themeAndStringsPromise.get()) |> mapToQueue { sortedContacts, selectionState, themeAndStrings -> Signal in let signal = deferred { () -> Signal in - let entries = inviteContactsEntries(accountPeer: nil, sortedContacts: sortedContacts, selectionState: selectionState, theme: themeAndStrings.0, strings: themeAndStrings.1, interaction: interaction) + let entries = inviteContactsEntries(accountPeer: nil, sortedContacts: sortedContacts, selectionState: selectionState, theme: themeAndStrings.0, strings: themeAndStrings.1, nameSortOrder: themeAndStrings.2, nameDisplayOrder: themeAndStrings.3, interaction: interaction) let previous = previousEntries.swap(entries) let animated: Bool if let previous = previous { @@ -485,6 +491,10 @@ final class InviteContactsControllerNode: ASDisplayNode { self.searchDisplayController?.updateThemeAndStrings(theme: self.presentationData.theme, strings: self.presentationData.strings) } + func scrollToTop() { + self.listNode.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: [.Synchronous, .LowLatency], scrollToItem: ListViewScrollToItem(index: 0, position: .top(0.0), animated: true, curve: .Default, directionHint: .Up), updateSizeAndInsets: nil, stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in }) + } + func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) { let hadValidLayout = self.validLayout != nil self.validLayout = (layout, navigationBarHeight) diff --git a/TelegramUI/ItemListAvatarAndNameItem.swift b/TelegramUI/ItemListAvatarAndNameItem.swift index 97994d8b85..1e0f0c8a4a 100644 --- a/TelegramUI/ItemListAvatarAndNameItem.swift +++ b/TelegramUI/ItemListAvatarAndNameItem.swift @@ -696,7 +696,6 @@ class ItemListAvatarAndNameInfoItemNode: ListViewItemNode, ItemListItemNode, Ite strongSelf.inputSeparator = inputSeparator } - //let title = title.prefix(255) if strongSelf.inputFirstField == nil { let inputFirstField = TextFieldNodeView() @@ -712,12 +711,12 @@ class ItemListAvatarAndNameInfoItemNode: ListViewItemNode, ItemListItemNode, Ite placeholder = item.strings.GroupInfo_ChannelListNamePlaceholder } inputFirstField.attributedPlaceholder = NSAttributedString(string: placeholder, font: Font.regular(19.0), textColor: item.theme.list.itemPlaceholderTextColor) - inputFirstField.attributedText = NSAttributedString(string: String(title), font: Font.regular(19.0), textColor: item.theme.list.itemPrimaryTextColor) + inputFirstField.attributedText = NSAttributedString(string: title, font: Font.regular(19.0), textColor: item.theme.list.itemPrimaryTextColor) strongSelf.inputFirstField = inputFirstField strongSelf.view.addSubview(inputFirstField) inputFirstField.addTarget(self, action: #selector(strongSelf.textFieldDidChange(_:)), for: .editingChanged) - } else if strongSelf.inputFirstField?.text != String(title) { - strongSelf.inputFirstField?.text = String(title) + } else if strongSelf.inputFirstField?.text != title { + strongSelf.inputFirstField?.text = title } strongSelf.inputSeparator?.frame = CGRect(origin: CGPoint(x: params.leftInset + 100.0, y: 62.0), size: CGSize(width: params.width - params.leftInset - params.rightInset - 100.0, height: separatorHeight)) diff --git a/TelegramUI/ItemListController.swift b/TelegramUI/ItemListController.swift index a1ff39c726..28e160d987 100644 --- a/TelegramUI/ItemListController.swift +++ b/TelegramUI/ItemListController.swift @@ -141,7 +141,7 @@ class ItemListController: ViewController { private var didPlayPresentationAnimation = false private(set) var didAppearOnce = false - var didAppear: (() -> Void)? + var didAppear: ((Bool) -> Void)? var titleControlValueChanged: ((Int) -> Void)? @@ -186,16 +186,20 @@ class ItemListController: ViewController { var willDisappear: ((Bool) -> Void)? - init(account: Account, state: Signal<(ItemListControllerState, (ItemListNodeState, Entry.ItemGenerationArguments)), NoError>, tabBarItem: Signal? = nil) { + convenience init(account: Account, state: Signal<(ItemListControllerState, (ItemListNodeState, Entry.ItemGenerationArguments)), NoError>, tabBarItem: Signal? = nil) { + let presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 } + self.init(theme: presentationData.theme, strings: presentationData.strings, updatedPresentationData: account.telegramApplicationContext.presentationData |> map { ($0.theme, $0.strings) }, state: state, tabBarItem: tabBarItem) + } + + init(theme: PresentationTheme, strings: PresentationStrings, updatedPresentationData: Signal<(theme: PresentationTheme, strings: PresentationStrings), NoError>, state: Signal<(ItemListControllerState, (ItemListNodeState, Entry.ItemGenerationArguments)), NoError>, tabBarItem: Signal?) { self.state = state - let presentationData = (account.telegramApplicationContext.currentPresentationData.with { $0 }) - self.theme = presentationData.theme - self.strings = presentationData.strings + self.theme = theme + self.strings = strings - super.init(navigationBarPresentationData: NavigationBarPresentationData(presentationData: presentationData)) + super.init(navigationBarPresentationData: NavigationBarPresentationData(theme: NavigationBarTheme(rootControllerTheme: theme), strings: NavigationBarStrings(presentationStrings: strings))) - self.statusBar.statusBarStyle = (account.telegramApplicationContext.currentPresentationData.with { $0 }).theme.rootController.statusBar.style.style + self.statusBar.statusBarStyle = theme.rootController.statusBar.style.style self.scrollToTop = { [weak self] in (self?.displayNode as! ItemListControllerNode).scrollToTop() @@ -415,10 +419,8 @@ class ItemListController: ViewController { } } - if !self.didAppearOnce { - self.didAppearOnce = true - self.didAppear?() - } + self.didAppear?(!self.didAppearOnce) + self.didAppearOnce = true } override func viewWillDisappear(_ animated: Bool) { diff --git a/TelegramUI/ItemListSingleLineInputItem.swift b/TelegramUI/ItemListSingleLineInputItem.swift index 8dbde90424..77e8c42d3a 100644 --- a/TelegramUI/ItemListSingleLineInputItem.swift +++ b/TelegramUI/ItemListSingleLineInputItem.swift @@ -333,7 +333,7 @@ class ItemListSingleLineInputItemNode: ListViewItemNode, UITextFieldDelegate, It } } - @objc func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { + @objc internal func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { if string.count > 1, let item = self.item, let processPaste = item.processPaste { let result = processPaste(string) if result != string { @@ -352,4 +352,9 @@ class ItemListSingleLineInputItemNode: ListViewItemNode, UITextFieldDelegate, It } return true } + + @objc internal func textFieldShouldReturn(_ textField: UITextField) -> Bool { + self.item?.action() + return false + } } diff --git a/TelegramUI/LegacyAvatarPicker.swift b/TelegramUI/LegacyAvatarPicker.swift new file mode 100644 index 0000000000..e225c42816 --- /dev/null +++ b/TelegramUI/LegacyAvatarPicker.swift @@ -0,0 +1,37 @@ +import Foundation +import Display +import SwiftSignalKit +import LegacyComponents + +func presentLegacyAvatarPicker(holder: Atomic, signup: Bool, theme: PresentationTheme, present: (ViewController, Any?) -> Void, completion: @escaping (UIImage) -> Void) { + let legacyController = LegacyController(presentation: .custom, theme: theme) + legacyController.statusBar.statusBarStyle = .Ignore + + let emptyController = LegacyEmptyController(context: legacyController.context)! + let navigationController = makeLegacyNavigationController(rootController: emptyController) + navigationController.setNavigationBarHidden(true, animated: false) + navigationController.navigationBar.transform = CGAffineTransform(translationX: -1000.0, y: 0.0) + + legacyController.bind(controller: navigationController) + + present(legacyController, nil) + + let mixin = TGMediaAvatarMenuMixin(context: legacyController.context, parentController: emptyController, hasDeleteButton: false, hasViewButton: false, personalPhoto: true, saveEditedPhotos: false, saveCapturedMedia: false, signup: signup)! + let _ = holder.swap(mixin) + mixin.didFinishWithImage = { image in + guard let image = image else { + return + } + completion(image) + } + mixin.didDismiss = { [weak legacyController] in + let _ = holder.swap(nil) + legacyController?.dismiss() + } + let menuController = mixin.present() + if let menuController = menuController { + menuController.customRemoveFromParentViewController = { [weak legacyController] in + legacyController?.dismiss() + } + } +} diff --git a/TelegramUI/MediaPlayerAudioRenderer.swift b/TelegramUI/MediaPlayerAudioRenderer.swift index c751b2892a..b2f1d327c4 100644 --- a/TelegramUI/MediaPlayerAudioRenderer.swift +++ b/TelegramUI/MediaPlayerAudioRenderer.swift @@ -417,6 +417,10 @@ private final class AudioPlayerRendererContext { return } + var maximumFramesPerSlice: UInt32 = 4096 + AudioUnitSetProperty(converterAudioUnit, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, &maximumFramesPerSlice, 4) + AudioUnitSetProperty(timePitchAudioUnit, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, &maximumFramesPerSlice, 4) + guard AUGraphInitialize(audioGraph) == noErr else { return } diff --git a/TelegramUI/MessageContentKind.swift b/TelegramUI/MessageContentKind.swift index 34c95c9ef0..d988b868d4 100644 --- a/TelegramUI/MessageContentKind.swift +++ b/TelegramUI/MessageContentKind.swift @@ -2,7 +2,24 @@ import Foundation import Postbox import TelegramCore -enum MessageContentKind: Equatable { +public enum MessageContentKindKey { + case text + case image + case video + case videoMessage + case audioMessage + case sticker + case animation + case file + case contact + case game + case location + case liveLocation + case expiredImage + case expiredVideo +} + +public enum MessageContentKind: Equatable { case text(String) case image case video @@ -18,97 +35,41 @@ enum MessageContentKind: Equatable { case expiredImage case expiredVideo - static func ==(lhs: MessageContentKind, rhs: MessageContentKind) -> Bool { - switch lhs { - case let .text(text): - if case .text(text) = rhs { - return true - } else { - return false - } + public var key: MessageContentKindKey { + switch self { + case .text: + return .text case .image: - if case .image = rhs { - return true - } else { - return false - } + return .image case .video: - if case .video = rhs { - return true - } else { - return false - } + return .video case .videoMessage: - if case .videoMessage = rhs { - return true - } else { - return false - } + return .videoMessage case .audioMessage: - if case .audioMessage = rhs { - return true - } else { - return false - } - case let .sticker(text): - if case .sticker(text) = rhs { - return true - } else { - return false - } + return .audioMessage + case .sticker: + return .sticker case .animation: - if case .animation = rhs { - return true - } else { - return false - } - case let .file(text): - if case .file(text) = rhs { - return true - } else { - return false - } + return .animation + case .file: + return .file case .contact: - if case .contact = rhs { - return true - } else { - return false - } - case let .game(text): - if case .game(text) = rhs { - return true - } else { - return false - } + return .contact + case .game: + return .game case .location: - if case .location = rhs { - return true - } else { - return false - } + return .location case .liveLocation: - if case .liveLocation = rhs { - return true - } else { - return false - } + return .liveLocation case .expiredImage: - if case .expiredImage = rhs { - return true - } else { - return false - } + return .expiredImage case .expiredVideo: - if case .expiredVideo = rhs { - return true - } else { - return false - } + return .expiredVideo } } } -func messageContentKind(_ message: Message, strings: PresentationStrings, accountPeerId: PeerId) -> MessageContentKind { +public func messageContentKind(_ message: Message, strings: PresentationStrings, accountPeerId: PeerId) -> MessageContentKind { for media in message.media { switch media { case let expiredMedia as TelegramMediaExpiredContent: diff --git a/TelegramUI/OngoingCallThreadLocalContext.mm b/TelegramUI/OngoingCallThreadLocalContext.mm index 40894cafeb..c2a5054369 100644 --- a/TelegramUI/OngoingCallThreadLocalContext.mm +++ b/TelegramUI/OngoingCallThreadLocalContext.mm @@ -257,14 +257,15 @@ static int callControllerNetworkTypeForType(OngoingCallNetworkType type) { config.logFilePath = ""; config.statsDumpFilePath = ""; - _controller->SetConfig(config); - - _controller->SetEncryptionKey((char *)key.bytes, isOutgoing); - /*releasable*/ - _controller->SetRemoteEndpoints(endpoints, _allowP2P, maxLayer); - _controller->Start(); - - _controller->Connect(); + if (_controller != nil) { + _controller->SetConfig(config); + + _controller->SetEncryptionKey((char *)key.bytes, isOutgoing); + _controller->SetRemoteEndpoints(endpoints, _allowP2P, maxLayer); + _controller->Start(); + + _controller->Connect(); + } } - (void)stop { diff --git a/TelegramUI/PeerChannelMemberCategoriesContextsManager.swift b/TelegramUI/PeerChannelMemberCategoriesContextsManager.swift index 3040135ea0..20361d2895 100644 --- a/TelegramUI/PeerChannelMemberCategoriesContextsManager.swift +++ b/TelegramUI/PeerChannelMemberCategoriesContextsManager.swift @@ -3,41 +3,22 @@ import Postbox import TelegramCore import SwiftSignalKit -enum PeerChannelMemberContextKey: Hashable { +enum PeerChannelMemberContextKey: Equatable, Hashable { case recent case recentSearch(String) case admins(String?) case restrictedAndBanned(String?) var hashValue: Int { - return 0 - } - static func ==(lhs: PeerChannelMemberContextKey, rhs: PeerChannelMemberContextKey) -> Bool { - switch lhs { - case .recent: - if case .recent = rhs { - return true - } else { - return false - } - case let .recentSearch(query): - if case .recentSearch(query) = rhs { - return true - } else { - return false - } - case let .admins(query): - if case .admins(query) = rhs { - return true - } else { - return false - } - case let .restrictedAndBanned(query): - if case .restrictedAndBanned(query) = rhs { - return true - } else { - return false - } + switch self { + case .recent: + return 1 + case let .recentSearch(query): + return query.hashValue + case let .admins(query): + return query?.hashValue ?? 2 + case let .restrictedAndBanned(query): + return query?.hashValue ?? 3 } } } @@ -208,7 +189,7 @@ final class PeerChannelMemberCategoriesContextsManager { } } |> mapToSignal { _ -> Signal in - return .complete() + return .single(Void()) } } } diff --git a/TelegramUI/PeerReportController.swift b/TelegramUI/PeerReportController.swift index c9bfb3895b..d0fb8a9b90 100644 --- a/TelegramUI/PeerReportController.swift +++ b/TelegramUI/PeerReportController.swift @@ -223,7 +223,11 @@ private func peerReportController(account: Account, subject: PeerReportSubject) if !text.isEmpty { let completed: () -> Void = { let presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 } - presentControllerImpl?(OverlayStatusController(theme: presentationData.theme, type: .success), nil) + + let alert = standardTextAlertController(theme: AlertControllerTheme(presentationTheme: presentationData.theme), title: nil, text: presentationData.strings.ReportPeer_AlertSuccess, actions: [TextAlertAction.init(type: TextAlertActionType.defaultAction, title: presentationData.strings.Common_OK, action: { + + })]) + presentControllerImpl?(alert, nil) dismissImpl?() } switch subject { diff --git a/TelegramUI/PeerSelectionControllerNode.swift b/TelegramUI/PeerSelectionControllerNode.swift index 7aaffa00e8..660a6e7f40 100644 --- a/TelegramUI/PeerSelectionControllerNode.swift +++ b/TelegramUI/PeerSelectionControllerNode.swift @@ -62,7 +62,7 @@ final class PeerSelectionControllerNode: ASDisplayNode { self.segmentedControl.tintColor = self.presentationData.theme.rootController.navigationBar.accentTextColor self.segmentedControl.selectedSegmentIndex = 0 - self.chatListNode = ChatListNode(account: account, groupId: nil, controlsHistoryPreload: false, mode: .peers(filter: filter), theme: presentationData.theme, strings: presentationData.strings, timeFormat: presentationData.timeFormat) + self.chatListNode = ChatListNode(account: account, groupId: nil, controlsHistoryPreload: false, mode: .peers(filter: filter), theme: presentationData.theme, strings: presentationData.strings, timeFormat: presentationData.timeFormat, nameSortOrder: presentationData.nameSortOrder, nameDisplayOrder: presentationData.nameDisplayOrder) super.init() @@ -107,7 +107,7 @@ final class PeerSelectionControllerNode: ASDisplayNode { private func updateThemeAndStrings() { self.searchDisplayController?.updateThemeAndStrings(theme: self.presentationData.theme, strings: self.presentationData.strings) - self.chatListNode.updateThemeAndStrings(theme: self.presentationData.theme, strings: self.presentationData.strings, timeFormat: self.presentationData.timeFormat) + self.chatListNode.updateThemeAndStrings(theme: self.presentationData.theme, strings: self.presentationData.strings, timeFormat: self.presentationData.timeFormat, nameSortOrder: self.presentationData.nameSortOrder, nameDisplayOrder: self.presentationData.nameDisplayOrder) } func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) { diff --git a/TelegramUI/PresentationData.swift b/TelegramUI/PresentationData.swift index 64c318da8c..fc3dc71bfb 100644 --- a/TelegramUI/PresentationData.swift +++ b/TelegramUI/PresentationData.swift @@ -2,25 +2,38 @@ import Foundation import SwiftSignalKit import Postbox import TelegramCore +import Contacts +import AddressBook public enum PresentationTimeFormat { case regular case military } +public enum PresentationPersonNameOrder { + case firstLast + case lastFirst +} + + + public final class PresentationData: Equatable { public let strings: PresentationStrings public let theme: PresentationTheme public let chatWallpaper: TelegramWallpaper public let fontSize: PresentationFontSize public let timeFormat: PresentationTimeFormat + public let nameDisplayOrder: PresentationPersonNameOrder + public let nameSortOrder: PresentationPersonNameOrder - public init(strings: PresentationStrings, theme: PresentationTheme, chatWallpaper: TelegramWallpaper, fontSize: PresentationFontSize, timeFormat: PresentationTimeFormat) { + public init(strings: PresentationStrings, theme: PresentationTheme, chatWallpaper: TelegramWallpaper, fontSize: PresentationFontSize, timeFormat: PresentationTimeFormat, nameDisplayOrder: PresentationPersonNameOrder, nameSortOrder: PresentationPersonNameOrder) { self.strings = strings self.theme = theme self.chatWallpaper = chatWallpaper self.fontSize = fontSize self.timeFormat = timeFormat + self.nameDisplayOrder = nameDisplayOrder + self.nameSortOrder = nameSortOrder } public static func ==(lhs: PresentationData, rhs: PresentationData) -> Bool { @@ -71,6 +84,40 @@ private func currentTimeFormat() -> PresentationTimeFormat { } } +private func currentPersonNameSortOrder() -> PresentationPersonNameOrder { + if #available(iOSApplicationExtension 9.0, *) { + switch CNContactsUserDefaults.shared().sortOrder { + case .givenName: + return .firstLast + default: + return .lastFirst + } + } else { + if ABPersonGetSortOrdering() == kABPersonSortByFirstName { + return .firstLast + } else { + return .lastFirst + } + } +} + +private func currentPersonNameDisplayOrder() -> PresentationPersonNameOrder { + if #available(iOSApplicationExtension 9.0, *) { + switch CNContactFormatter.nameOrder(for: CNContact()) { + case .givenNameFirst: + return .firstLast + default: + return .lastFirst + } + } else { + if ABPersonGetCompositeNameFormat() == kABPersonCompositeNameFormatFirstNameFirst { + return .firstLast + } else { + return .lastFirst + } + } +} + public final class InitialPresentationDataAndSettings { public let presentationData: PresentationData public let automaticMediaDownloadSettings: AutomaticMediaDownloadSettings @@ -185,8 +232,10 @@ public func currentPresentationDataAndSettings(postbox: Postbox) -> Signal Signal (String, [(Int, NSRange)]) { return formatWithArgumentRanges(_PHONE_CALL_REQUEST, self._PHONE_CALL_REQUEST_r, [_1]) } + public let AccessDenied_MicrophoneRestricted: String + public let Your_cards_expiration_year_is_invalid: String public let GroupInfo_InviteByLink: String private let _Notification_LeftChat: String private let _Notification_LeftChat_r: [(Int, NSRange)] @@ -222,11 +223,6 @@ public final class PresentationStrings { public func PrivacyPolicy_AgeVerificationMessage(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(_PrivacyPolicy_AgeVerificationMessage, self._PrivacyPolicy_AgeVerificationMessage_r, [_0]) } - private let _Login_TermsOfService_ProceedBot: String - private let _Login_TermsOfService_ProceedBot_r: [(Int, NSRange)] - public func Login_TermsOfService_ProceedBot(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(_Login_TermsOfService_ProceedBot, self._Login_TermsOfService_ProceedBot_r, [_0]) - } public let NotificationsSound_None: String public let Channel_AdminLog_CanEditMessages: String private let _MESSAGE_CONTACT: String @@ -1391,18 +1387,6 @@ public final class PresentationStrings { public func Channel_AdminLog_MessageKickedNameUsername(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(_Channel_AdminLog_MessageKickedNameUsername, self._Channel_AdminLog_MessageKickedNameUsername_r, [_1, _2]) } - private let _Channel_AdminLog_MessageUnkickedNameUsername: String - private let _Channel_AdminLog_MessageUnkickedNameUsername_r: [(Int, NSRange)] - public func Channel_AdminLog_MessageUnkickedNameUsername(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(_Channel_AdminLog_MessageUnkickedNameUsername, self._Channel_AdminLog_MessageUnkickedNameUsername_r, [_1, _2]) - } - - private let _Channel_AdminLog_MessageUnkickedName: String - private let _Channel_AdminLog_MessageUnkickedName_r: [(Int, NSRange)] - public func Channel_AdminLog_MessageUnkickedName(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(_Channel_AdminLog_MessageUnkickedName, self._Channel_AdminLog_MessageUnkickedName_r, [_1]) - } - public let Coub_TapForSound: String public let Compose_NewEncryptedChat: String public let PhotoEditor_CropReset: String @@ -1668,6 +1652,11 @@ public final class PresentationStrings { public let Conversation_GifTooltip: String public let Passport_Address_EditBankStatement: String public let CheckoutInfo_ErrorCityInvalid: String + private let _CHANNEL_MESSAGE_PHOTOS: String + private let _CHANNEL_MESSAGE_PHOTOS_r: [(Int, NSRange)] + public func CHANNEL_MESSAGE_PHOTOS(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(_CHANNEL_MESSAGE_PHOTOS, self._CHANNEL_MESSAGE_PHOTOS_r, [_1, _2]) + } public let Profile_CreateEncryptedChatError: String public let Map_LocationTitle: String public let Call_RateCall: String @@ -1706,6 +1695,11 @@ public final class PresentationStrings { public let Group_ErrorSendRestrictedStickers: String public let Bot_GroupStatusDoesNotReadHistory: String public let Notification_Mute1h: String + private let _Channel_AdminLog_MessageUnkickedName: String + private let _Channel_AdminLog_MessageUnkickedName_r: [(Int, NSRange)] + public func Channel_AdminLog_MessageUnkickedName(_ _1: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(_Channel_AdminLog_MessageUnkickedName, self._Channel_AdminLog_MessageUnkickedName_r, [_1]) + } public let Settings_TabTitle: String public let Passport_Identity_ExpiryDatePlaceholder: String public let NetworkUsageSettings_MediaAudioDataSection: String @@ -1734,6 +1728,11 @@ public final class PresentationStrings { return formatWithArgumentRanges(_Conversation_RestrictedStickersTimed, self._Conversation_RestrictedStickersTimed_r, [_0]) } public let Login_InvalidFirstNameError: String + private let _Channel_AdminLog_MessageUnkickedNameUsername: String + private let _Channel_AdminLog_MessageUnkickedNameUsername_r: [(Int, NSRange)] + public func Channel_AdminLog_MessageUnkickedNameUsername(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(_Channel_AdminLog_MessageUnkickedNameUsername, self._Channel_AdminLog_MessageUnkickedNameUsername_r, [_1, _2]) + } private let _Notification_Joined: String private let _Notification_Joined_r: [(Int, NSRange)] public func Notification_Joined(_ _0: String) -> (String, [(Int, NSRange)]) { @@ -1861,6 +1860,11 @@ public final class PresentationStrings { public let MediaPicker_TimerTooltip: String public let Activity_UploadingVideo: String public let Channel_Info_Management: String + private let _Login_TermsOfService_ProceedBot: String + private let _Login_TermsOfService_ProceedBot_r: [(Int, NSRange)] + public func Login_TermsOfService_ProceedBot(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(_Login_TermsOfService_ProceedBot, self._Login_TermsOfService_ProceedBot_r, [_0]) + } private let _Notification_MessageLifetimeChangedOutgoing: String private let _Notification_MessageLifetimeChangedOutgoing_r: [(Int, NSRange)] public func Notification_MessageLifetimeChangedOutgoing(_ _1: String) -> (String, [(Int, NSRange)]) { @@ -1883,6 +1887,11 @@ public final class PresentationStrings { public let Contacts_AccessDeniedHelpON: String public let Passport_Identity_AddInternalPassport: String public let NetworkUsageSettings_ResetStats: String + private let _CHAT_MESSAGE_PHOTOS: String + private let _CHAT_MESSAGE_PHOTOS_r: [(Int, NSRange)] + public func CHAT_MESSAGE_PHOTOS(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(_CHAT_MESSAGE_PHOTOS, self._CHAT_MESSAGE_PHOTOS_r, [_1, _2, _3]) + } private let _PrivacySettings_LastSeenContactsMinusPlus: String private let _PrivacySettings_LastSeenContactsMinusPlus_r: [(Int, NSRange)] public func PrivacySettings_LastSeenContactsMinusPlus(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { @@ -2255,6 +2264,11 @@ public final class PresentationStrings { public let Activity_UploadingVideoMessage: String public let Conversation_ShareBotContactConfirmation: String public let Login_CodeSentSms: String + private let _CHANNEL_MESSAGES: String + private let _CHANNEL_MESSAGES_r: [(Int, NSRange)] + public func CHANNEL_MESSAGES(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(_CHANNEL_MESSAGES, self._CHANNEL_MESSAGES_r, [_1, _2]) + } public let Conversation_ReportSpamConfirmation: String public let ChannelMembers_ChannelAdminsTitle: String public let SocksProxySetup_Credentials: String @@ -2691,6 +2705,7 @@ public final class PresentationStrings { return formatWithArgumentRanges(_CHAT_ADD_YOU, self._CHAT_ADD_YOU_r, [_1, _2]) } public let CheckoutInfo_ShippingInfoCity: String + public let Group_AdminLog_EmptyText: String public let AutoDownloadSettings_GroupChats: String public let Conversation_ClousStorageInfo_Description3: String public let Notifications_ExceptionsMuted: String @@ -2929,8 +2944,7 @@ public final class PresentationStrings { public let Watch_Location_Access: String public let PrivacySettings_DeleteAccountIfAwayFor: String public let Channel_AdminLog_EmptyFilterText: String - public let Channel_AdminLog_EmptyText: String - public let Group_AdminLog_EmptyText: String + public let Broadcast_AdminLog_EmptyText: String public let PrivacySettings_DeleteAccountTitle: String public let Passport_Language_ms: String public let PrivacyLastSeenSettings_CustomShareSettings_Delete: String @@ -2990,11 +3004,15 @@ public final class PresentationStrings { public let AccessDenied_Title: String public let SharedMedia_CategoryLinks: String public let Localization_LanguageOther: String + private let _CHAT_MESSAGES: String + private let _CHAT_MESSAGES_r: [(Int, NSRange)] + public func CHAT_MESSAGES(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(_CHAT_MESSAGES, self._CHAT_MESSAGES_r, [_1, _2, _3]) + } public let SaveIncomingPhotosSettings_Title: String public let Passport_Identity_TypeDriversLicense: String public let FastTwoStepSetup_HintHelp: String public let Notifications_ExceptionsDefaultSound: String - public let Passport_Language_es: String public let TwoStepAuth_EmailSkipAlert: String public let ChatSettings_Stickers: String public let Camera_FlashOff: String @@ -3006,6 +3024,7 @@ public final class PresentationStrings { public let Conversation_typing: String public let Common_Back: String public let PrivacySettings_DataSettingsHelp: String + public let Passport_Language_es: String public let Common_Search: String private let _CancelResetAccount_Success: String private let _CancelResetAccount_Success_r: [(Int, NSRange)] @@ -3201,10 +3220,10 @@ public final class PresentationStrings { public let MediaPicker_CameraRoll: String public let Channel_AdminLog_CanPinMessages: String public let KeyCommand_NewMessage: String - private let _Time_PreciseDate_m12: String - private let _Time_PreciseDate_m12_r: [(Int, NSRange)] - public func Time_PreciseDate_m12(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(_Time_PreciseDate_m12, self._Time_PreciseDate_m12_r, [_1, _2, _3]) + private let _ChannelInfo_AddParticipantConfirmation: String + private let _ChannelInfo_AddParticipantConfirmation_r: [(Int, NSRange)] + public func ChannelInfo_AddParticipantConfirmation(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(_ChannelInfo_AddParticipantConfirmation, self._ChannelInfo_AddParticipantConfirmation_r, [_0]) } public let NetworkUsageSettings_TotalSection: String private let _PINNED_AUDIO: String @@ -3213,6 +3232,11 @@ public final class PresentationStrings { return formatWithArgumentRanges(_PINNED_AUDIO, self._PINNED_AUDIO_r, [_1]) } public let Privacy_GroupsAndChannels: String + private let _Time_PreciseDate_m12: String + private let _Time_PreciseDate_m12_r: [(Int, NSRange)] + public func Time_PreciseDate_m12(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(_Time_PreciseDate_m12, self._Time_PreciseDate_m12_r, [_1, _2, _3]) + } public let Conversation_DiscardVoiceMessageDescription: String public let Passport_Address_ScansHelp: String private let _Notification_ChangedGroupPhoto: String @@ -3259,10 +3283,15 @@ public final class PresentationStrings { public let Group_ErrorAddTooMuchAdmins: String public let SocksProxySetup_Password: String public let Login_SelectCountry_Title: String - public let UserInfo_NotificationsDefault: String + private let _MESSAGE_PHOTOS: String + private let _MESSAGE_PHOTOS_r: [(Int, NSRange)] + public func MESSAGE_PHOTOS(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(_MESSAGE_PHOTOS, self._MESSAGE_PHOTOS_r, [_1, _2]) + } public let Notifications_GroupNotificationsHelp: String public let PhotoEditor_CropAspectRatioSquare: String public let Notification_CallOutgoing: String + public let UserInfo_NotificationsDefault: String public let Weekday_ShortMonday: String public let Checkout_Receipt_Title: String public let Channel_Edit_AboutItem: String @@ -3291,11 +3320,6 @@ public final class PresentationStrings { public func ChannelInfo_ChannelForbidden(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(_ChannelInfo_ChannelForbidden, self._ChannelInfo_ChannelForbidden_r, [_0]) } - private let _ChannelInfo_AddParticipantConfirmation: String - private let _ChannelInfo_AddParticipantConfirmation_r: [(Int, NSRange)] - public func ChannelInfo_AddParticipantConfirmation(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(_ChannelInfo_AddParticipantConfirmation, self._ChannelInfo_AddParticipantConfirmation_r, [_0]) - } public let Conversation_ShareMyContactInfo: String public let SocksProxySetup_UsernamePlaceholder: String private let _CHANNEL_MESSAGE_GEO: String @@ -3483,6 +3507,11 @@ public final class PresentationStrings { public let Map_OpenInGoogleMaps: String public let Notification_MessageLifetime5s: String public let Contacts_Title: String + private let _MESSAGES: String + private let _MESSAGES_r: [(Int, NSRange)] + public func MESSAGES(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(_MESSAGES, self._MESSAGES_r, [_1, _2]) + } public let Channel_Management_AddModeratorHelp: String private let _CHAT_MESSAGE_FWDS: String private let _CHAT_MESSAGE_FWDS_r: [(Int, NSRange)] @@ -3536,8 +3565,8 @@ public final class PresentationStrings { public let ExplicitContent_AlertTitle: String public let Channel_AdminLogFilter_EventsLeaving: String public let Map_LiveLocationFor8Hours: String - public let Checkout_EnterPassword: String public let StickerPack_HideStickers: String + public let Checkout_EnterPassword: String public let UserInfo_NotificationsEnabled: String public let InfoPlist_NSLocationAlwaysUsageDescription: String public let SocksProxySetup_ProxyDetailsTitle: String @@ -3559,72 +3588,6 @@ public final class PresentationStrings { public let PrivacySettings_PasscodeAndFaceId: String public let Settings_ChatBackground: String public let Login_TermsOfServiceDecline: String - private let _ForwardedFiles_zero: String - private let _ForwardedFiles_one: String - private let _ForwardedFiles_two: String - private let _ForwardedFiles_few: String - private let _ForwardedFiles_many: String - private let _ForwardedFiles_other: String - public func ForwardedFiles(_ value: Int32) -> String { - switch presentationStringsPluralizationForm(self.lc, value) { - case .zero: - return String(format: self._ForwardedFiles_zero, "\(value)") - case .one: - return String(format: self._ForwardedFiles_one, "\(value)") - case .two: - return String(format: self._ForwardedFiles_two, "\(value)") - case .few: - return String(format: self._ForwardedFiles_few, "\(value)") - case .many: - return String(format: self._ForwardedFiles_many, "\(value)") - case .other: - return String(format: self._ForwardedFiles_other, "\(value)") - } - } - private let _Watch_LastSeen_HoursAgo_zero: String - private let _Watch_LastSeen_HoursAgo_one: String - private let _Watch_LastSeen_HoursAgo_two: String - private let _Watch_LastSeen_HoursAgo_few: String - private let _Watch_LastSeen_HoursAgo_many: String - private let _Watch_LastSeen_HoursAgo_other: String - public func Watch_LastSeen_HoursAgo(_ value: Int32) -> String { - switch presentationStringsPluralizationForm(self.lc, value) { - case .zero: - return String(format: self._Watch_LastSeen_HoursAgo_zero, "\(value)") - case .one: - return String(format: self._Watch_LastSeen_HoursAgo_one, "\(value)") - case .two: - return String(format: self._Watch_LastSeen_HoursAgo_two, "\(value)") - case .few: - return String(format: self._Watch_LastSeen_HoursAgo_few, "\(value)") - case .many: - return String(format: self._Watch_LastSeen_HoursAgo_many, "\(value)") - case .other: - return String(format: self._Watch_LastSeen_HoursAgo_other, "\(value)") - } - } - private let _MessageTimer_ShortDays_zero: String - private let _MessageTimer_ShortDays_one: String - private let _MessageTimer_ShortDays_two: String - private let _MessageTimer_ShortDays_few: String - private let _MessageTimer_ShortDays_many: String - private let _MessageTimer_ShortDays_other: String - public func MessageTimer_ShortDays(_ value: Int32) -> String { - switch presentationStringsPluralizationForm(self.lc, value) { - case .zero: - return String(format: self._MessageTimer_ShortDays_zero, "\(value)") - case .one: - return String(format: self._MessageTimer_ShortDays_one, "\(value)") - case .two: - return String(format: self._MessageTimer_ShortDays_two, "\(value)") - case .few: - return String(format: self._MessageTimer_ShortDays_few, "\(value)") - case .many: - return String(format: self._MessageTimer_ShortDays_many, "\(value)") - case .other: - return String(format: self._MessageTimer_ShortDays_other, "\(value)") - } - } private let _LastSeen_MinutesAgo_zero: String private let _LastSeen_MinutesAgo_one: String private let _LastSeen_MinutesAgo_two: String @@ -3669,202 +3632,26 @@ public final class PresentationStrings { return String(format: self._MuteFor_Days_other, "\(value)") } } - private let _MessageTimer_Months_zero: String - private let _MessageTimer_Months_one: String - private let _MessageTimer_Months_two: String - private let _MessageTimer_Months_few: String - private let _MessageTimer_Months_many: String - private let _MessageTimer_Months_other: String - public func MessageTimer_Months(_ value: Int32) -> String { + private let _StickerPack_AddStickerCount_zero: String + private let _StickerPack_AddStickerCount_one: String + private let _StickerPack_AddStickerCount_two: String + private let _StickerPack_AddStickerCount_few: String + private let _StickerPack_AddStickerCount_many: String + private let _StickerPack_AddStickerCount_other: String + public func StickerPack_AddStickerCount(_ value: Int32) -> String { switch presentationStringsPluralizationForm(self.lc, value) { case .zero: - return String(format: self._MessageTimer_Months_zero, "\(value)") + return String(format: self._StickerPack_AddStickerCount_zero, "\(value)") case .one: - return String(format: self._MessageTimer_Months_one, "\(value)") + return String(format: self._StickerPack_AddStickerCount_one, "\(value)") case .two: - return String(format: self._MessageTimer_Months_two, "\(value)") + return String(format: self._StickerPack_AddStickerCount_two, "\(value)") case .few: - return String(format: self._MessageTimer_Months_few, "\(value)") + return String(format: self._StickerPack_AddStickerCount_few, "\(value)") case .many: - return String(format: self._MessageTimer_Months_many, "\(value)") + return String(format: self._StickerPack_AddStickerCount_many, "\(value)") case .other: - return String(format: self._MessageTimer_Months_other, "\(value)") - } - } - private let _PasscodeSettings_FailedAttempts_zero: String - private let _PasscodeSettings_FailedAttempts_one: String - private let _PasscodeSettings_FailedAttempts_two: String - private let _PasscodeSettings_FailedAttempts_few: String - private let _PasscodeSettings_FailedAttempts_many: String - private let _PasscodeSettings_FailedAttempts_other: String - public func PasscodeSettings_FailedAttempts(_ value: Int32) -> String { - switch presentationStringsPluralizationForm(self.lc, value) { - case .zero: - return String(format: self._PasscodeSettings_FailedAttempts_zero, "\(value)") - case .one: - return String(format: self._PasscodeSettings_FailedAttempts_one, "\(value)") - case .two: - return String(format: self._PasscodeSettings_FailedAttempts_two, "\(value)") - case .few: - return String(format: self._PasscodeSettings_FailedAttempts_few, "\(value)") - case .many: - return String(format: self._PasscodeSettings_FailedAttempts_many, "\(value)") - case .other: - return String(format: self._PasscodeSettings_FailedAttempts_other, "\(value)") - } - } - private let _ServiceMessage_GameScoreSimple_zero: String - private let _ServiceMessage_GameScoreSimple_one: String - private let _ServiceMessage_GameScoreSimple_two: String - private let _ServiceMessage_GameScoreSimple_few: String - private let _ServiceMessage_GameScoreSimple_many: String - private let _ServiceMessage_GameScoreSimple_other: String - public func ServiceMessage_GameScoreSimple(_ value: Int32) -> String { - switch presentationStringsPluralizationForm(self.lc, value) { - case .zero: - return String(format: self._ServiceMessage_GameScoreSimple_zero, "\(value)") - case .one: - return String(format: self._ServiceMessage_GameScoreSimple_one, "\(value)") - case .two: - return String(format: self._ServiceMessage_GameScoreSimple_two, "\(value)") - case .few: - return String(format: self._ServiceMessage_GameScoreSimple_few, "\(value)") - case .many: - return String(format: self._ServiceMessage_GameScoreSimple_many, "\(value)") - case .other: - return String(format: self._ServiceMessage_GameScoreSimple_other, "\(value)") - } - } - private let _MessageTimer_ShortWeeks_zero: String - private let _MessageTimer_ShortWeeks_one: String - private let _MessageTimer_ShortWeeks_two: String - private let _MessageTimer_ShortWeeks_few: String - private let _MessageTimer_ShortWeeks_many: String - private let _MessageTimer_ShortWeeks_other: String - public func MessageTimer_ShortWeeks(_ value: Int32) -> String { - switch presentationStringsPluralizationForm(self.lc, value) { - case .zero: - return String(format: self._MessageTimer_ShortWeeks_zero, "\(value)") - case .one: - return String(format: self._MessageTimer_ShortWeeks_one, "\(value)") - case .two: - return String(format: self._MessageTimer_ShortWeeks_two, "\(value)") - case .few: - return String(format: self._MessageTimer_ShortWeeks_few, "\(value)") - case .many: - return String(format: self._MessageTimer_ShortWeeks_many, "\(value)") - case .other: - return String(format: self._MessageTimer_ShortWeeks_other, "\(value)") - } - } - private let _MuteExpires_Days_zero: String - private let _MuteExpires_Days_one: String - private let _MuteExpires_Days_two: String - private let _MuteExpires_Days_few: String - private let _MuteExpires_Days_many: String - private let _MuteExpires_Days_other: String - public func MuteExpires_Days(_ value: Int32) -> String { - switch presentationStringsPluralizationForm(self.lc, value) { - case .zero: - return String(format: self._MuteExpires_Days_zero, "\(value)") - case .one: - return String(format: self._MuteExpires_Days_one, "\(value)") - case .two: - return String(format: self._MuteExpires_Days_two, "\(value)") - case .few: - return String(format: self._MuteExpires_Days_few, "\(value)") - case .many: - return String(format: self._MuteExpires_Days_many, "\(value)") - case .other: - return String(format: self._MuteExpires_Days_other, "\(value)") - } - } - private let _Notification_GameScoreExtended_zero: String - private let _Notification_GameScoreExtended_one: String - private let _Notification_GameScoreExtended_two: String - private let _Notification_GameScoreExtended_few: String - private let _Notification_GameScoreExtended_many: String - private let _Notification_GameScoreExtended_other: String - public func Notification_GameScoreExtended(_ value: Int32) -> String { - switch presentationStringsPluralizationForm(self.lc, value) { - case .zero: - return String(format: self._Notification_GameScoreExtended_zero, "\(value)") - case .one: - return String(format: self._Notification_GameScoreExtended_one, "\(value)") - case .two: - return String(format: self._Notification_GameScoreExtended_two, "\(value)") - case .few: - return String(format: self._Notification_GameScoreExtended_few, "\(value)") - case .many: - return String(format: self._Notification_GameScoreExtended_many, "\(value)") - case .other: - return String(format: self._Notification_GameScoreExtended_other, "\(value)") - } - } - private let _Notifications_Exceptions_zero: String - private let _Notifications_Exceptions_one: String - private let _Notifications_Exceptions_two: String - private let _Notifications_Exceptions_few: String - private let _Notifications_Exceptions_many: String - private let _Notifications_Exceptions_other: String - public func Notifications_Exceptions(_ value: Int32) -> String { - switch presentationStringsPluralizationForm(self.lc, value) { - case .zero: - return String(format: self._Notifications_Exceptions_zero, "\(value)") - case .one: - return String(format: self._Notifications_Exceptions_one, "\(value)") - case .two: - return String(format: self._Notifications_Exceptions_two, "\(value)") - case .few: - return String(format: self._Notifications_Exceptions_few, "\(value)") - case .many: - return String(format: self._Notifications_Exceptions_many, "\(value)") - case .other: - return String(format: self._Notifications_Exceptions_other, "\(value)") - } - } - private let _DialogList_LiveLocationChatsCount_zero: String - private let _DialogList_LiveLocationChatsCount_one: String - private let _DialogList_LiveLocationChatsCount_two: String - private let _DialogList_LiveLocationChatsCount_few: String - private let _DialogList_LiveLocationChatsCount_many: String - private let _DialogList_LiveLocationChatsCount_other: String - public func DialogList_LiveLocationChatsCount(_ value: Int32) -> String { - switch presentationStringsPluralizationForm(self.lc, value) { - case .zero: - return String(format: self._DialogList_LiveLocationChatsCount_zero, "\(value)") - case .one: - return String(format: self._DialogList_LiveLocationChatsCount_one, "\(value)") - case .two: - return String(format: self._DialogList_LiveLocationChatsCount_two, "\(value)") - case .few: - return String(format: self._DialogList_LiveLocationChatsCount_few, "\(value)") - case .many: - return String(format: self._DialogList_LiveLocationChatsCount_many, "\(value)") - case .other: - return String(format: self._DialogList_LiveLocationChatsCount_other, "\(value)") - } - } - private let _ForwardedAuthorsOthers_zero: String - private let _ForwardedAuthorsOthers_one: String - private let _ForwardedAuthorsOthers_two: String - private let _ForwardedAuthorsOthers_few: String - private let _ForwardedAuthorsOthers_many: String - private let _ForwardedAuthorsOthers_other: String - public func ForwardedAuthorsOthers(_ value: Int32) -> String { - switch presentationStringsPluralizationForm(self.lc, value) { - case .zero: - return String(format: self._ForwardedAuthorsOthers_zero, "\(value)") - case .one: - return String(format: self._ForwardedAuthorsOthers_one, "\(value)") - case .two: - return String(format: self._ForwardedAuthorsOthers_two, "\(value)") - case .few: - return String(format: self._ForwardedAuthorsOthers_few, "\(value)") - case .many: - return String(format: self._ForwardedAuthorsOthers_many, "\(value)") - case .other: - return String(format: self._ForwardedAuthorsOthers_other, "\(value)") + return String(format: self._StickerPack_AddStickerCount_other, "\(value)") } } private let _StickerPack_AddMaskCount_zero: String @@ -3889,180 +3676,70 @@ public final class PresentationStrings { return String(format: self._StickerPack_AddMaskCount_other, "\(value)") } } - private let _ServiceMessage_GameScoreSelfExtended_zero: String - private let _ServiceMessage_GameScoreSelfExtended_one: String - private let _ServiceMessage_GameScoreSelfExtended_two: String - private let _ServiceMessage_GameScoreSelfExtended_few: String - private let _ServiceMessage_GameScoreSelfExtended_many: String - private let _ServiceMessage_GameScoreSelfExtended_other: String - public func ServiceMessage_GameScoreSelfExtended(_ value: Int32) -> String { + private let _Notification_GameScoreSimple_zero: String + private let _Notification_GameScoreSimple_one: String + private let _Notification_GameScoreSimple_two: String + private let _Notification_GameScoreSimple_few: String + private let _Notification_GameScoreSimple_many: String + private let _Notification_GameScoreSimple_other: String + public func Notification_GameScoreSimple(_ value: Int32) -> String { switch presentationStringsPluralizationForm(self.lc, value) { case .zero: - return String(format: self._ServiceMessage_GameScoreSelfExtended_zero, "\(value)") + return String(format: self._Notification_GameScoreSimple_zero, "\(value)") case .one: - return String(format: self._ServiceMessage_GameScoreSelfExtended_one, "\(value)") + return String(format: self._Notification_GameScoreSimple_one, "\(value)") case .two: - return String(format: self._ServiceMessage_GameScoreSelfExtended_two, "\(value)") + return String(format: self._Notification_GameScoreSimple_two, "\(value)") case .few: - return String(format: self._ServiceMessage_GameScoreSelfExtended_few, "\(value)") + return String(format: self._Notification_GameScoreSimple_few, "\(value)") case .many: - return String(format: self._ServiceMessage_GameScoreSelfExtended_many, "\(value)") + return String(format: self._Notification_GameScoreSimple_many, "\(value)") case .other: - return String(format: self._ServiceMessage_GameScoreSelfExtended_other, "\(value)") + return String(format: self._Notification_GameScoreSimple_other, "\(value)") } } - private let _Map_ETAHours_zero: String - private let _Map_ETAHours_one: String - private let _Map_ETAHours_two: String - private let _Map_ETAHours_few: String - private let _Map_ETAHours_many: String - private let _Map_ETAHours_other: String - public func Map_ETAHours(_ value: Int32) -> String { + private let _Media_SharePhoto_zero: String + private let _Media_SharePhoto_one: String + private let _Media_SharePhoto_two: String + private let _Media_SharePhoto_few: String + private let _Media_SharePhoto_many: String + private let _Media_SharePhoto_other: String + public func Media_SharePhoto(_ value: Int32) -> String { switch presentationStringsPluralizationForm(self.lc, value) { case .zero: - return String(format: self._Map_ETAHours_zero, "\(value)") + return String(format: self._Media_SharePhoto_zero, "\(value)") case .one: - return String(format: self._Map_ETAHours_one, "\(value)") + return String(format: self._Media_SharePhoto_one, "\(value)") case .two: - return String(format: self._Map_ETAHours_two, "\(value)") + return String(format: self._Media_SharePhoto_two, "\(value)") case .few: - return String(format: self._Map_ETAHours_few, "\(value)") + return String(format: self._Media_SharePhoto_few, "\(value)") case .many: - return String(format: self._Map_ETAHours_many, "\(value)") + return String(format: self._Media_SharePhoto_many, "\(value)") case .other: - return String(format: self._Map_ETAHours_other, "\(value)") + return String(format: self._Media_SharePhoto_other, "\(value)") } } - private let _SharedMedia_File_zero: String - private let _SharedMedia_File_one: String - private let _SharedMedia_File_two: String - private let _SharedMedia_File_few: String - private let _SharedMedia_File_many: String - private let _SharedMedia_File_other: String - public func SharedMedia_File(_ value: Int32) -> String { + private let _SharedMedia_Photo_zero: String + private let _SharedMedia_Photo_one: String + private let _SharedMedia_Photo_two: String + private let _SharedMedia_Photo_few: String + private let _SharedMedia_Photo_many: String + private let _SharedMedia_Photo_other: String + public func SharedMedia_Photo(_ value: Int32) -> String { switch presentationStringsPluralizationForm(self.lc, value) { case .zero: - return String(format: self._SharedMedia_File_zero, "\(value)") + return String(format: self._SharedMedia_Photo_zero, "\(value)") case .one: - return String(format: self._SharedMedia_File_one, "\(value)") + return String(format: self._SharedMedia_Photo_one, "\(value)") case .two: - return String(format: self._SharedMedia_File_two, "\(value)") + return String(format: self._SharedMedia_Photo_two, "\(value)") case .few: - return String(format: self._SharedMedia_File_few, "\(value)") + return String(format: self._SharedMedia_Photo_few, "\(value)") case .many: - return String(format: self._SharedMedia_File_many, "\(value)") + return String(format: self._SharedMedia_Photo_many, "\(value)") case .other: - return String(format: self._SharedMedia_File_other, "\(value)") - } - } - private let _MessageTimer_Days_zero: String - private let _MessageTimer_Days_one: String - private let _MessageTimer_Days_two: String - private let _MessageTimer_Days_few: String - private let _MessageTimer_Days_many: String - private let _MessageTimer_Days_other: String - public func MessageTimer_Days(_ value: Int32) -> String { - switch presentationStringsPluralizationForm(self.lc, value) { - case .zero: - return String(format: self._MessageTimer_Days_zero, "\(value)") - case .one: - return String(format: self._MessageTimer_Days_one, "\(value)") - case .two: - return String(format: self._MessageTimer_Days_two, "\(value)") - case .few: - return String(format: self._MessageTimer_Days_few, "\(value)") - case .many: - return String(format: self._MessageTimer_Days_many, "\(value)") - case .other: - return String(format: self._MessageTimer_Days_other, "\(value)") - } - } - private let _ForwardedStickers_zero: String - private let _ForwardedStickers_one: String - private let _ForwardedStickers_two: String - private let _ForwardedStickers_few: String - private let _ForwardedStickers_many: String - private let _ForwardedStickers_other: String - public func ForwardedStickers(_ value: Int32) -> String { - switch presentationStringsPluralizationForm(self.lc, value) { - case .zero: - return String(format: self._ForwardedStickers_zero, "\(value)") - case .one: - return String(format: self._ForwardedStickers_one, "\(value)") - case .two: - return String(format: self._ForwardedStickers_two, "\(value)") - case .few: - return String(format: self._ForwardedStickers_few, "\(value)") - case .many: - return String(format: self._ForwardedStickers_many, "\(value)") - case .other: - return String(format: self._ForwardedStickers_other, "\(value)") - } - } - private let _ServiceMessage_GameScoreExtended_zero: String - private let _ServiceMessage_GameScoreExtended_one: String - private let _ServiceMessage_GameScoreExtended_two: String - private let _ServiceMessage_GameScoreExtended_few: String - private let _ServiceMessage_GameScoreExtended_many: String - private let _ServiceMessage_GameScoreExtended_other: String - public func ServiceMessage_GameScoreExtended(_ value: Int32) -> String { - switch presentationStringsPluralizationForm(self.lc, value) { - case .zero: - return String(format: self._ServiceMessage_GameScoreExtended_zero, "\(value)") - case .one: - return String(format: self._ServiceMessage_GameScoreExtended_one, "\(value)") - case .two: - return String(format: self._ServiceMessage_GameScoreExtended_two, "\(value)") - case .few: - return String(format: self._ServiceMessage_GameScoreExtended_few, "\(value)") - case .many: - return String(format: self._ServiceMessage_GameScoreExtended_many, "\(value)") - case .other: - return String(format: self._ServiceMessage_GameScoreExtended_other, "\(value)") - } - } - private let _ServiceMessage_GameScoreSelfSimple_zero: String - private let _ServiceMessage_GameScoreSelfSimple_one: String - private let _ServiceMessage_GameScoreSelfSimple_two: String - private let _ServiceMessage_GameScoreSelfSimple_few: String - private let _ServiceMessage_GameScoreSelfSimple_many: String - private let _ServiceMessage_GameScoreSelfSimple_other: String - public func ServiceMessage_GameScoreSelfSimple(_ value: Int32) -> String { - switch presentationStringsPluralizationForm(self.lc, value) { - case .zero: - return String(format: self._ServiceMessage_GameScoreSelfSimple_zero, "\(value)") - case .one: - return String(format: self._ServiceMessage_GameScoreSelfSimple_one, "\(value)") - case .two: - return String(format: self._ServiceMessage_GameScoreSelfSimple_two, "\(value)") - case .few: - return String(format: self._ServiceMessage_GameScoreSelfSimple_few, "\(value)") - case .many: - return String(format: self._ServiceMessage_GameScoreSelfSimple_many, "\(value)") - case .other: - return String(format: self._ServiceMessage_GameScoreSelfSimple_other, "\(value)") - } - } - private let _LiveLocation_MenuChatsCount_zero: String - private let _LiveLocation_MenuChatsCount_one: String - private let _LiveLocation_MenuChatsCount_two: String - private let _LiveLocation_MenuChatsCount_few: String - private let _LiveLocation_MenuChatsCount_many: String - private let _LiveLocation_MenuChatsCount_other: String - public func LiveLocation_MenuChatsCount(_ value: Int32) -> String { - switch presentationStringsPluralizationForm(self.lc, value) { - case .zero: - return String(format: self._LiveLocation_MenuChatsCount_zero, "\(value)") - case .one: - return String(format: self._LiveLocation_MenuChatsCount_one, "\(value)") - case .two: - return String(format: self._LiveLocation_MenuChatsCount_two, "\(value)") - case .few: - return String(format: self._LiveLocation_MenuChatsCount_few, "\(value)") - case .many: - return String(format: self._LiveLocation_MenuChatsCount_many, "\(value)") - case .other: - return String(format: self._LiveLocation_MenuChatsCount_other, "\(value)") + return String(format: self._SharedMedia_Photo_other, "\(value)") } } private let _MessageTimer_ShortSeconds_zero: String @@ -4087,136 +3764,48 @@ public final class PresentationStrings { return String(format: self._MessageTimer_ShortSeconds_other, "\(value)") } } - private let _ForwardedGifs_zero: String - private let _ForwardedGifs_one: String - private let _ForwardedGifs_two: String - private let _ForwardedGifs_few: String - private let _ForwardedGifs_many: String - private let _ForwardedGifs_other: String - public func ForwardedGifs(_ value: Int32) -> String { + private let _AttachmentMenu_SendItem_zero: String + private let _AttachmentMenu_SendItem_one: String + private let _AttachmentMenu_SendItem_two: String + private let _AttachmentMenu_SendItem_few: String + private let _AttachmentMenu_SendItem_many: String + private let _AttachmentMenu_SendItem_other: String + public func AttachmentMenu_SendItem(_ value: Int32) -> String { switch presentationStringsPluralizationForm(self.lc, value) { case .zero: - return String(format: self._ForwardedGifs_zero, "\(value)") + return String(format: self._AttachmentMenu_SendItem_zero, "\(value)") case .one: - return String(format: self._ForwardedGifs_one, "\(value)") + return String(format: self._AttachmentMenu_SendItem_one, "\(value)") case .two: - return String(format: self._ForwardedGifs_two, "\(value)") + return String(format: self._AttachmentMenu_SendItem_two, "\(value)") case .few: - return String(format: self._ForwardedGifs_few, "\(value)") + return String(format: self._AttachmentMenu_SendItem_few, "\(value)") case .many: - return String(format: self._ForwardedGifs_many, "\(value)") + return String(format: self._AttachmentMenu_SendItem_many, "\(value)") case .other: - return String(format: self._ForwardedGifs_other, "\(value)") + return String(format: self._AttachmentMenu_SendItem_other, "\(value)") } } - private let _MuteFor_Hours_zero: String - private let _MuteFor_Hours_one: String - private let _MuteFor_Hours_two: String - private let _MuteFor_Hours_few: String - private let _MuteFor_Hours_many: String - private let _MuteFor_Hours_other: String - public func MuteFor_Hours(_ value: Int32) -> String { + private let _SharedMedia_DeleteItemsConfirmation_zero: String + private let _SharedMedia_DeleteItemsConfirmation_one: String + private let _SharedMedia_DeleteItemsConfirmation_two: String + private let _SharedMedia_DeleteItemsConfirmation_few: String + private let _SharedMedia_DeleteItemsConfirmation_many: String + private let _SharedMedia_DeleteItemsConfirmation_other: String + public func SharedMedia_DeleteItemsConfirmation(_ value: Int32) -> String { switch presentationStringsPluralizationForm(self.lc, value) { case .zero: - return String(format: self._MuteFor_Hours_zero, "\(value)") + return String(format: self._SharedMedia_DeleteItemsConfirmation_zero, "\(value)") case .one: - return String(format: self._MuteFor_Hours_one, "\(value)") + return String(format: self._SharedMedia_DeleteItemsConfirmation_one, "\(value)") case .two: - return String(format: self._MuteFor_Hours_two, "\(value)") + return String(format: self._SharedMedia_DeleteItemsConfirmation_two, "\(value)") case .few: - return String(format: self._MuteFor_Hours_few, "\(value)") + return String(format: self._SharedMedia_DeleteItemsConfirmation_few, "\(value)") case .many: - return String(format: self._MuteFor_Hours_many, "\(value)") + return String(format: self._SharedMedia_DeleteItemsConfirmation_many, "\(value)") case .other: - return String(format: self._MuteFor_Hours_other, "\(value)") - } - } - private let _StickerPack_StickerCount_zero: String - private let _StickerPack_StickerCount_one: String - private let _StickerPack_StickerCount_two: String - private let _StickerPack_StickerCount_few: String - private let _StickerPack_StickerCount_many: String - private let _StickerPack_StickerCount_other: String - public func StickerPack_StickerCount(_ value: Int32) -> String { - switch presentationStringsPluralizationForm(self.lc, value) { - case .zero: - return String(format: self._StickerPack_StickerCount_zero, "\(value)") - case .one: - return String(format: self._StickerPack_StickerCount_one, "\(value)") - case .two: - return String(format: self._StickerPack_StickerCount_two, "\(value)") - case .few: - return String(format: self._StickerPack_StickerCount_few, "\(value)") - case .many: - return String(format: self._StickerPack_StickerCount_many, "\(value)") - case .other: - return String(format: self._StickerPack_StickerCount_other, "\(value)") - } - } - private let _Passport_Scans_zero: String - private let _Passport_Scans_one: String - private let _Passport_Scans_two: String - private let _Passport_Scans_few: String - private let _Passport_Scans_many: String - private let _Passport_Scans_other: String - public func Passport_Scans(_ value: Int32) -> String { - switch presentationStringsPluralizationForm(self.lc, value) { - case .zero: - return String(format: self._Passport_Scans_zero, "\(value)") - case .one: - return String(format: self._Passport_Scans_one, "\(value)") - case .two: - return String(format: self._Passport_Scans_two, "\(value)") - case .few: - return String(format: self._Passport_Scans_few, "\(value)") - case .many: - return String(format: self._Passport_Scans_many, "\(value)") - case .other: - return String(format: self._Passport_Scans_other, "\(value)") - } - } - private let _Notification_GameScoreSelfSimple_zero: String - private let _Notification_GameScoreSelfSimple_one: String - private let _Notification_GameScoreSelfSimple_two: String - private let _Notification_GameScoreSelfSimple_few: String - private let _Notification_GameScoreSelfSimple_many: String - private let _Notification_GameScoreSelfSimple_other: String - public func Notification_GameScoreSelfSimple(_ value: Int32) -> String { - switch presentationStringsPluralizationForm(self.lc, value) { - case .zero: - return String(format: self._Notification_GameScoreSelfSimple_zero, "\(value)") - case .one: - return String(format: self._Notification_GameScoreSelfSimple_one, "\(value)") - case .two: - return String(format: self._Notification_GameScoreSelfSimple_two, "\(value)") - case .few: - return String(format: self._Notification_GameScoreSelfSimple_few, "\(value)") - case .many: - return String(format: self._Notification_GameScoreSelfSimple_many, "\(value)") - case .other: - return String(format: self._Notification_GameScoreSelfSimple_other, "\(value)") - } - } - private let _ForwardedVideos_zero: String - private let _ForwardedVideos_one: String - private let _ForwardedVideos_two: String - private let _ForwardedVideos_few: String - private let _ForwardedVideos_many: String - private let _ForwardedVideos_other: String - public func ForwardedVideos(_ value: Int32) -> String { - switch presentationStringsPluralizationForm(self.lc, value) { - case .zero: - return String(format: self._ForwardedVideos_zero, "\(value)") - case .one: - return String(format: self._ForwardedVideos_one, "\(value)") - case .two: - return String(format: self._ForwardedVideos_two, "\(value)") - case .few: - return String(format: self._ForwardedVideos_few, "\(value)") - case .many: - return String(format: self._ForwardedVideos_many, "\(value)") - case .other: - return String(format: self._ForwardedVideos_other, "\(value)") + return String(format: self._SharedMedia_DeleteItemsConfirmation_other, "\(value)") } } private let _MessageTimer_ShortHours_zero: String @@ -4241,26 +3830,92 @@ public final class PresentationStrings { return String(format: self._MessageTimer_ShortHours_other, "\(value)") } } - private let _ForwardedContacts_zero: String - private let _ForwardedContacts_one: String - private let _ForwardedContacts_two: String - private let _ForwardedContacts_few: String - private let _ForwardedContacts_many: String - private let _ForwardedContacts_other: String - public func ForwardedContacts(_ value: Int32) -> String { + private let _MuteExpires_Days_zero: String + private let _MuteExpires_Days_one: String + private let _MuteExpires_Days_two: String + private let _MuteExpires_Days_few: String + private let _MuteExpires_Days_many: String + private let _MuteExpires_Days_other: String + public func MuteExpires_Days(_ value: Int32) -> String { switch presentationStringsPluralizationForm(self.lc, value) { case .zero: - return String(format: self._ForwardedContacts_zero, "\(value)") + return String(format: self._MuteExpires_Days_zero, "\(value)") case .one: - return String(format: self._ForwardedContacts_one, "\(value)") + return String(format: self._MuteExpires_Days_one, "\(value)") case .two: - return String(format: self._ForwardedContacts_two, "\(value)") + return String(format: self._MuteExpires_Days_two, "\(value)") case .few: - return String(format: self._ForwardedContacts_few, "\(value)") + return String(format: self._MuteExpires_Days_few, "\(value)") case .many: - return String(format: self._ForwardedContacts_many, "\(value)") + return String(format: self._MuteExpires_Days_many, "\(value)") case .other: - return String(format: self._ForwardedContacts_other, "\(value)") + return String(format: self._MuteExpires_Days_other, "\(value)") + } + } + private let _Passport_Scans_zero: String + private let _Passport_Scans_one: String + private let _Passport_Scans_two: String + private let _Passport_Scans_few: String + private let _Passport_Scans_many: String + private let _Passport_Scans_other: String + public func Passport_Scans(_ value: Int32) -> String { + switch presentationStringsPluralizationForm(self.lc, value) { + case .zero: + return String(format: self._Passport_Scans_zero, "\(value)") + case .one: + return String(format: self._Passport_Scans_one, "\(value)") + case .two: + return String(format: self._Passport_Scans_two, "\(value)") + case .few: + return String(format: self._Passport_Scans_few, "\(value)") + case .many: + return String(format: self._Passport_Scans_many, "\(value)") + case .other: + return String(format: self._Passport_Scans_other, "\(value)") + } + } + private let _MessageTimer_Hours_zero: String + private let _MessageTimer_Hours_one: String + private let _MessageTimer_Hours_two: String + private let _MessageTimer_Hours_few: String + private let _MessageTimer_Hours_many: String + private let _MessageTimer_Hours_other: String + public func MessageTimer_Hours(_ value: Int32) -> String { + switch presentationStringsPluralizationForm(self.lc, value) { + case .zero: + return String(format: self._MessageTimer_Hours_zero, "\(value)") + case .one: + return String(format: self._MessageTimer_Hours_one, "\(value)") + case .two: + return String(format: self._MessageTimer_Hours_two, "\(value)") + case .few: + return String(format: self._MessageTimer_Hours_few, "\(value)") + case .many: + return String(format: self._MessageTimer_Hours_many, "\(value)") + case .other: + return String(format: self._MessageTimer_Hours_other, "\(value)") + } + } + private let _Notification_GameScoreExtended_zero: String + private let _Notification_GameScoreExtended_one: String + private let _Notification_GameScoreExtended_two: String + private let _Notification_GameScoreExtended_few: String + private let _Notification_GameScoreExtended_many: String + private let _Notification_GameScoreExtended_other: String + public func Notification_GameScoreExtended(_ value: Int32) -> String { + switch presentationStringsPluralizationForm(self.lc, value) { + case .zero: + return String(format: self._Notification_GameScoreExtended_zero, "\(value)") + case .one: + return String(format: self._Notification_GameScoreExtended_one, "\(value)") + case .two: + return String(format: self._Notification_GameScoreExtended_two, "\(value)") + case .few: + return String(format: self._Notification_GameScoreExtended_few, "\(value)") + case .many: + return String(format: self._Notification_GameScoreExtended_many, "\(value)") + case .other: + return String(format: self._Notification_GameScoreExtended_other, "\(value)") } } private let _ForwardedLocations_zero: String @@ -4285,6 +3940,270 @@ public final class PresentationStrings { return String(format: self._ForwardedLocations_other, "\(value)") } } + private let _ServiceMessage_GameScoreSelfSimple_zero: String + private let _ServiceMessage_GameScoreSelfSimple_one: String + private let _ServiceMessage_GameScoreSelfSimple_two: String + private let _ServiceMessage_GameScoreSelfSimple_few: String + private let _ServiceMessage_GameScoreSelfSimple_many: String + private let _ServiceMessage_GameScoreSelfSimple_other: String + public func ServiceMessage_GameScoreSelfSimple(_ value: Int32) -> String { + switch presentationStringsPluralizationForm(self.lc, value) { + case .zero: + return String(format: self._ServiceMessage_GameScoreSelfSimple_zero, "\(value)") + case .one: + return String(format: self._ServiceMessage_GameScoreSelfSimple_one, "\(value)") + case .two: + return String(format: self._ServiceMessage_GameScoreSelfSimple_two, "\(value)") + case .few: + return String(format: self._ServiceMessage_GameScoreSelfSimple_few, "\(value)") + case .many: + return String(format: self._ServiceMessage_GameScoreSelfSimple_many, "\(value)") + case .other: + return String(format: self._ServiceMessage_GameScoreSelfSimple_other, "\(value)") + } + } + private let _ForwardedPhotos_zero: String + private let _ForwardedPhotos_one: String + private let _ForwardedPhotos_two: String + private let _ForwardedPhotos_few: String + private let _ForwardedPhotos_many: String + private let _ForwardedPhotos_other: String + public func ForwardedPhotos(_ value: Int32) -> String { + switch presentationStringsPluralizationForm(self.lc, value) { + case .zero: + return String(format: self._ForwardedPhotos_zero, "\(value)") + case .one: + return String(format: self._ForwardedPhotos_one, "\(value)") + case .two: + return String(format: self._ForwardedPhotos_two, "\(value)") + case .few: + return String(format: self._ForwardedPhotos_few, "\(value)") + case .many: + return String(format: self._ForwardedPhotos_many, "\(value)") + case .other: + return String(format: self._ForwardedPhotos_other, "\(value)") + } + } + private let _LiveLocationUpdated_MinutesAgo_zero: String + private let _LiveLocationUpdated_MinutesAgo_one: String + private let _LiveLocationUpdated_MinutesAgo_two: String + private let _LiveLocationUpdated_MinutesAgo_few: String + private let _LiveLocationUpdated_MinutesAgo_many: String + private let _LiveLocationUpdated_MinutesAgo_other: String + public func LiveLocationUpdated_MinutesAgo(_ value: Int32) -> String { + switch presentationStringsPluralizationForm(self.lc, value) { + case .zero: + return String(format: self._LiveLocationUpdated_MinutesAgo_zero, "\(value)") + case .one: + return String(format: self._LiveLocationUpdated_MinutesAgo_one, "\(value)") + case .two: + return String(format: self._LiveLocationUpdated_MinutesAgo_two, "\(value)") + case .few: + return String(format: self._LiveLocationUpdated_MinutesAgo_few, "\(value)") + case .many: + return String(format: self._LiveLocationUpdated_MinutesAgo_many, "\(value)") + case .other: + return String(format: self._LiveLocationUpdated_MinutesAgo_other, "\(value)") + } + } + private let _StickerPack_RemoveMaskCount_zero: String + private let _StickerPack_RemoveMaskCount_one: String + private let _StickerPack_RemoveMaskCount_two: String + private let _StickerPack_RemoveMaskCount_few: String + private let _StickerPack_RemoveMaskCount_many: String + private let _StickerPack_RemoveMaskCount_other: String + public func StickerPack_RemoveMaskCount(_ value: Int32) -> String { + switch presentationStringsPluralizationForm(self.lc, value) { + case .zero: + return String(format: self._StickerPack_RemoveMaskCount_zero, "\(value)") + case .one: + return String(format: self._StickerPack_RemoveMaskCount_one, "\(value)") + case .two: + return String(format: self._StickerPack_RemoveMaskCount_two, "\(value)") + case .few: + return String(format: self._StickerPack_RemoveMaskCount_few, "\(value)") + case .many: + return String(format: self._StickerPack_RemoveMaskCount_many, "\(value)") + case .other: + return String(format: self._StickerPack_RemoveMaskCount_other, "\(value)") + } + } + private let _SharedMedia_File_zero: String + private let _SharedMedia_File_one: String + private let _SharedMedia_File_two: String + private let _SharedMedia_File_few: String + private let _SharedMedia_File_many: String + private let _SharedMedia_File_other: String + public func SharedMedia_File(_ value: Int32) -> String { + switch presentationStringsPluralizationForm(self.lc, value) { + case .zero: + return String(format: self._SharedMedia_File_zero, "\(value)") + case .one: + return String(format: self._SharedMedia_File_one, "\(value)") + case .two: + return String(format: self._SharedMedia_File_two, "\(value)") + case .few: + return String(format: self._SharedMedia_File_few, "\(value)") + case .many: + return String(format: self._SharedMedia_File_many, "\(value)") + case .other: + return String(format: self._SharedMedia_File_other, "\(value)") + } + } + private let _MuteExpires_Hours_zero: String + private let _MuteExpires_Hours_one: String + private let _MuteExpires_Hours_two: String + private let _MuteExpires_Hours_few: String + private let _MuteExpires_Hours_many: String + private let _MuteExpires_Hours_other: String + public func MuteExpires_Hours(_ value: Int32) -> String { + switch presentationStringsPluralizationForm(self.lc, value) { + case .zero: + return String(format: self._MuteExpires_Hours_zero, "\(value)") + case .one: + return String(format: self._MuteExpires_Hours_one, "\(value)") + case .two: + return String(format: self._MuteExpires_Hours_two, "\(value)") + case .few: + return String(format: self._MuteExpires_Hours_few, "\(value)") + case .many: + return String(format: self._MuteExpires_Hours_many, "\(value)") + case .other: + return String(format: self._MuteExpires_Hours_other, "\(value)") + } + } + private let _MessageTimer_Seconds_zero: String + private let _MessageTimer_Seconds_one: String + private let _MessageTimer_Seconds_two: String + private let _MessageTimer_Seconds_few: String + private let _MessageTimer_Seconds_many: String + private let _MessageTimer_Seconds_other: String + public func MessageTimer_Seconds(_ value: Int32) -> String { + switch presentationStringsPluralizationForm(self.lc, value) { + case .zero: + return String(format: self._MessageTimer_Seconds_zero, "\(value)") + case .one: + return String(format: self._MessageTimer_Seconds_one, "\(value)") + case .two: + return String(format: self._MessageTimer_Seconds_two, "\(value)") + case .few: + return String(format: self._MessageTimer_Seconds_few, "\(value)") + case .many: + return String(format: self._MessageTimer_Seconds_many, "\(value)") + case .other: + return String(format: self._MessageTimer_Seconds_other, "\(value)") + } + } + private let _Notifications_ExceptionMuteExpires_Hours_zero: String + private let _Notifications_ExceptionMuteExpires_Hours_one: String + private let _Notifications_ExceptionMuteExpires_Hours_two: String + private let _Notifications_ExceptionMuteExpires_Hours_few: String + private let _Notifications_ExceptionMuteExpires_Hours_many: String + private let _Notifications_ExceptionMuteExpires_Hours_other: String + public func Notifications_ExceptionMuteExpires_Hours(_ value: Int32) -> String { + switch presentationStringsPluralizationForm(self.lc, value) { + case .zero: + return String(format: self._Notifications_ExceptionMuteExpires_Hours_zero, "\(value)") + case .one: + return String(format: self._Notifications_ExceptionMuteExpires_Hours_one, "\(value)") + case .two: + return String(format: self._Notifications_ExceptionMuteExpires_Hours_two, "\(value)") + case .few: + return String(format: self._Notifications_ExceptionMuteExpires_Hours_few, "\(value)") + case .many: + return String(format: self._Notifications_ExceptionMuteExpires_Hours_many, "\(value)") + case .other: + return String(format: self._Notifications_ExceptionMuteExpires_Hours_other, "\(value)") + } + } + private let _MuteFor_Hours_zero: String + private let _MuteFor_Hours_one: String + private let _MuteFor_Hours_two: String + private let _MuteFor_Hours_few: String + private let _MuteFor_Hours_many: String + private let _MuteFor_Hours_other: String + public func MuteFor_Hours(_ value: Int32) -> String { + switch presentationStringsPluralizationForm(self.lc, value) { + case .zero: + return String(format: self._MuteFor_Hours_zero, "\(value)") + case .one: + return String(format: self._MuteFor_Hours_one, "\(value)") + case .two: + return String(format: self._MuteFor_Hours_two, "\(value)") + case .few: + return String(format: self._MuteFor_Hours_few, "\(value)") + case .many: + return String(format: self._MuteFor_Hours_many, "\(value)") + case .other: + return String(format: self._MuteFor_Hours_other, "\(value)") + } + } + private let _MuteExpires_Minutes_zero: String + private let _MuteExpires_Minutes_one: String + private let _MuteExpires_Minutes_two: String + private let _MuteExpires_Minutes_few: String + private let _MuteExpires_Minutes_many: String + private let _MuteExpires_Minutes_other: String + public func MuteExpires_Minutes(_ value: Int32) -> String { + switch presentationStringsPluralizationForm(self.lc, value) { + case .zero: + return String(format: self._MuteExpires_Minutes_zero, "\(value)") + case .one: + return String(format: self._MuteExpires_Minutes_one, "\(value)") + case .two: + return String(format: self._MuteExpires_Minutes_two, "\(value)") + case .few: + return String(format: self._MuteExpires_Minutes_few, "\(value)") + case .many: + return String(format: self._MuteExpires_Minutes_many, "\(value)") + case .other: + return String(format: self._MuteExpires_Minutes_other, "\(value)") + } + } + private let _MessageTimer_ShortWeeks_zero: String + private let _MessageTimer_ShortWeeks_one: String + private let _MessageTimer_ShortWeeks_two: String + private let _MessageTimer_ShortWeeks_few: String + private let _MessageTimer_ShortWeeks_many: String + private let _MessageTimer_ShortWeeks_other: String + public func MessageTimer_ShortWeeks(_ value: Int32) -> String { + switch presentationStringsPluralizationForm(self.lc, value) { + case .zero: + return String(format: self._MessageTimer_ShortWeeks_zero, "\(value)") + case .one: + return String(format: self._MessageTimer_ShortWeeks_one, "\(value)") + case .two: + return String(format: self._MessageTimer_ShortWeeks_two, "\(value)") + case .few: + return String(format: self._MessageTimer_ShortWeeks_few, "\(value)") + case .many: + return String(format: self._MessageTimer_ShortWeeks_many, "\(value)") + case .other: + return String(format: self._MessageTimer_ShortWeeks_other, "\(value)") + } + } + private let _AttachmentMenu_SendPhoto_zero: String + private let _AttachmentMenu_SendPhoto_one: String + private let _AttachmentMenu_SendPhoto_two: String + private let _AttachmentMenu_SendPhoto_few: String + private let _AttachmentMenu_SendPhoto_many: String + private let _AttachmentMenu_SendPhoto_other: String + public func AttachmentMenu_SendPhoto(_ value: Int32) -> String { + switch presentationStringsPluralizationForm(self.lc, value) { + case .zero: + return String(format: self._AttachmentMenu_SendPhoto_zero, "\(value)") + case .one: + return String(format: self._AttachmentMenu_SendPhoto_one, "\(value)") + case .two: + return String(format: self._AttachmentMenu_SendPhoto_two, "\(value)") + case .few: + return String(format: self._AttachmentMenu_SendPhoto_few, "\(value)") + case .many: + return String(format: self._AttachmentMenu_SendPhoto_many, "\(value)") + case .other: + return String(format: self._AttachmentMenu_SendPhoto_other, "\(value)") + } + } private let _Notification_GameScoreSelfExtended_zero: String private let _Notification_GameScoreSelfExtended_one: String private let _Notification_GameScoreSelfExtended_two: String @@ -4329,664 +4248,48 @@ public final class PresentationStrings { return String(format: self._UserCount_other, "\(value)") } } - private let _SharedMedia_Generic_zero: String - private let _SharedMedia_Generic_one: String - private let _SharedMedia_Generic_two: String - private let _SharedMedia_Generic_few: String - private let _SharedMedia_Generic_many: String - private let _SharedMedia_Generic_other: String - public func SharedMedia_Generic(_ value: Int32) -> String { + private let _Notifications_ExceptionMuteExpires_Days_zero: String + private let _Notifications_ExceptionMuteExpires_Days_one: String + private let _Notifications_ExceptionMuteExpires_Days_two: String + private let _Notifications_ExceptionMuteExpires_Days_few: String + private let _Notifications_ExceptionMuteExpires_Days_many: String + private let _Notifications_ExceptionMuteExpires_Days_other: String + public func Notifications_ExceptionMuteExpires_Days(_ value: Int32) -> String { switch presentationStringsPluralizationForm(self.lc, value) { case .zero: - return String(format: self._SharedMedia_Generic_zero, "\(value)") + return String(format: self._Notifications_ExceptionMuteExpires_Days_zero, "\(value)") case .one: - return String(format: self._SharedMedia_Generic_one, "\(value)") + return String(format: self._Notifications_ExceptionMuteExpires_Days_one, "\(value)") case .two: - return String(format: self._SharedMedia_Generic_two, "\(value)") + return String(format: self._Notifications_ExceptionMuteExpires_Days_two, "\(value)") case .few: - return String(format: self._SharedMedia_Generic_few, "\(value)") + return String(format: self._Notifications_ExceptionMuteExpires_Days_few, "\(value)") case .many: - return String(format: self._SharedMedia_Generic_many, "\(value)") + return String(format: self._Notifications_ExceptionMuteExpires_Days_many, "\(value)") case .other: - return String(format: self._SharedMedia_Generic_other, "\(value)") + return String(format: self._Notifications_ExceptionMuteExpires_Days_other, "\(value)") } } - private let _Call_Minutes_zero: String - private let _Call_Minutes_one: String - private let _Call_Minutes_two: String - private let _Call_Minutes_few: String - private let _Call_Minutes_many: String - private let _Call_Minutes_other: String - public func Call_Minutes(_ value: Int32) -> String { + private let _Notifications_Exceptions_zero: String + private let _Notifications_Exceptions_one: String + private let _Notifications_Exceptions_two: String + private let _Notifications_Exceptions_few: String + private let _Notifications_Exceptions_many: String + private let _Notifications_Exceptions_other: String + public func Notifications_Exceptions(_ value: Int32) -> String { switch presentationStringsPluralizationForm(self.lc, value) { case .zero: - return String(format: self._Call_Minutes_zero, "\(value)") + return String(format: self._Notifications_Exceptions_zero, "\(value)") case .one: - return String(format: self._Call_Minutes_one, "\(value)") + return String(format: self._Notifications_Exceptions_one, "\(value)") case .two: - return String(format: self._Call_Minutes_two, "\(value)") + return String(format: self._Notifications_Exceptions_two, "\(value)") case .few: - return String(format: self._Call_Minutes_few, "\(value)") + return String(format: self._Notifications_Exceptions_few, "\(value)") case .many: - return String(format: self._Call_Minutes_many, "\(value)") + return String(format: self._Notifications_Exceptions_many, "\(value)") case .other: - return String(format: self._Call_Minutes_other, "\(value)") - } - } - private let _MessageTimer_ShortMinutes_zero: String - private let _MessageTimer_ShortMinutes_one: String - private let _MessageTimer_ShortMinutes_two: String - private let _MessageTimer_ShortMinutes_few: String - private let _MessageTimer_ShortMinutes_many: String - private let _MessageTimer_ShortMinutes_other: String - public func MessageTimer_ShortMinutes(_ value: Int32) -> String { - switch presentationStringsPluralizationForm(self.lc, value) { - case .zero: - return String(format: self._MessageTimer_ShortMinutes_zero, "\(value)") - case .one: - return String(format: self._MessageTimer_ShortMinutes_one, "\(value)") - case .two: - return String(format: self._MessageTimer_ShortMinutes_two, "\(value)") - case .few: - return String(format: self._MessageTimer_ShortMinutes_few, "\(value)") - case .many: - return String(format: self._MessageTimer_ShortMinutes_many, "\(value)") - case .other: - return String(format: self._MessageTimer_ShortMinutes_other, "\(value)") - } - } - private let _AttachmentMenu_SendVideo_zero: String - private let _AttachmentMenu_SendVideo_one: String - private let _AttachmentMenu_SendVideo_two: String - private let _AttachmentMenu_SendVideo_few: String - private let _AttachmentMenu_SendVideo_many: String - private let _AttachmentMenu_SendVideo_other: String - public func AttachmentMenu_SendVideo(_ value: Int32) -> String { - switch presentationStringsPluralizationForm(self.lc, value) { - case .zero: - return String(format: self._AttachmentMenu_SendVideo_zero, "\(value)") - case .one: - return String(format: self._AttachmentMenu_SendVideo_one, "\(value)") - case .two: - return String(format: self._AttachmentMenu_SendVideo_two, "\(value)") - case .few: - return String(format: self._AttachmentMenu_SendVideo_few, "\(value)") - case .many: - return String(format: self._AttachmentMenu_SendVideo_many, "\(value)") - case .other: - return String(format: self._AttachmentMenu_SendVideo_other, "\(value)") - } - } - private let _ForwardedMessages_zero: String - private let _ForwardedMessages_one: String - private let _ForwardedMessages_two: String - private let _ForwardedMessages_few: String - private let _ForwardedMessages_many: String - private let _ForwardedMessages_other: String - public func ForwardedMessages(_ value: Int32) -> String { - switch presentationStringsPluralizationForm(self.lc, value) { - case .zero: - return String(format: self._ForwardedMessages_zero, "\(value)") - case .one: - return String(format: self._ForwardedMessages_one, "\(value)") - case .two: - return String(format: self._ForwardedMessages_two, "\(value)") - case .few: - return String(format: self._ForwardedMessages_few, "\(value)") - case .many: - return String(format: self._ForwardedMessages_many, "\(value)") - case .other: - return String(format: self._ForwardedMessages_other, "\(value)") - } - } - private let _Conversation_StatusSubscribers_zero: String - private let _Conversation_StatusSubscribers_one: String - private let _Conversation_StatusSubscribers_two: String - private let _Conversation_StatusSubscribers_few: String - private let _Conversation_StatusSubscribers_many: String - private let _Conversation_StatusSubscribers_other: String - public func Conversation_StatusSubscribers(_ value: Int32) -> String { - switch presentationStringsPluralizationForm(self.lc, value) { - case .zero: - return String(format: self._Conversation_StatusSubscribers_zero, "\(value)") - case .one: - return String(format: self._Conversation_StatusSubscribers_one, "\(value)") - case .two: - return String(format: self._Conversation_StatusSubscribers_two, "\(value)") - case .few: - return String(format: self._Conversation_StatusSubscribers_few, "\(value)") - case .many: - return String(format: self._Conversation_StatusSubscribers_many, "\(value)") - case .other: - return String(format: self._Conversation_StatusSubscribers_other, "\(value)") - } - } - private let _SharedMedia_Photo_zero: String - private let _SharedMedia_Photo_one: String - private let _SharedMedia_Photo_two: String - private let _SharedMedia_Photo_few: String - private let _SharedMedia_Photo_many: String - private let _SharedMedia_Photo_other: String - public func SharedMedia_Photo(_ value: Int32) -> String { - switch presentationStringsPluralizationForm(self.lc, value) { - case .zero: - return String(format: self._SharedMedia_Photo_zero, "\(value)") - case .one: - return String(format: self._SharedMedia_Photo_one, "\(value)") - case .two: - return String(format: self._SharedMedia_Photo_two, "\(value)") - case .few: - return String(format: self._SharedMedia_Photo_few, "\(value)") - case .many: - return String(format: self._SharedMedia_Photo_many, "\(value)") - case .other: - return String(format: self._SharedMedia_Photo_other, "\(value)") - } - } - private let _GroupInfo_ParticipantCount_zero: String - private let _GroupInfo_ParticipantCount_one: String - private let _GroupInfo_ParticipantCount_two: String - private let _GroupInfo_ParticipantCount_few: String - private let _GroupInfo_ParticipantCount_many: String - private let _GroupInfo_ParticipantCount_other: String - public func GroupInfo_ParticipantCount(_ value: Int32) -> String { - switch presentationStringsPluralizationForm(self.lc, value) { - case .zero: - return String(format: self._GroupInfo_ParticipantCount_zero, "\(value)") - case .one: - return String(format: self._GroupInfo_ParticipantCount_one, "\(value)") - case .two: - return String(format: self._GroupInfo_ParticipantCount_two, "\(value)") - case .few: - return String(format: self._GroupInfo_ParticipantCount_few, "\(value)") - case .many: - return String(format: self._GroupInfo_ParticipantCount_many, "\(value)") - case .other: - return String(format: self._GroupInfo_ParticipantCount_other, "\(value)") - } - } - private let _Watch_UserInfo_Mute_zero: String - private let _Watch_UserInfo_Mute_one: String - private let _Watch_UserInfo_Mute_two: String - private let _Watch_UserInfo_Mute_few: String - private let _Watch_UserInfo_Mute_many: String - private let _Watch_UserInfo_Mute_other: String - public func Watch_UserInfo_Mute(_ value: Int32) -> String { - switch presentationStringsPluralizationForm(self.lc, value) { - case .zero: - return String(format: self._Watch_UserInfo_Mute_zero, "\(value)") - case .one: - return String(format: self._Watch_UserInfo_Mute_one, "\(value)") - case .two: - return String(format: self._Watch_UserInfo_Mute_two, "\(value)") - case .few: - return String(format: self._Watch_UserInfo_Mute_few, "\(value)") - case .many: - return String(format: self._Watch_UserInfo_Mute_many, "\(value)") - case .other: - return String(format: self._Watch_UserInfo_Mute_other, "\(value)") - } - } - private let _Forward_ConfirmMultipleFiles_zero: String - private let _Forward_ConfirmMultipleFiles_one: String - private let _Forward_ConfirmMultipleFiles_two: String - private let _Forward_ConfirmMultipleFiles_few: String - private let _Forward_ConfirmMultipleFiles_many: String - private let _Forward_ConfirmMultipleFiles_other: String - public func Forward_ConfirmMultipleFiles(_ value: Int32) -> String { - switch presentationStringsPluralizationForm(self.lc, value) { - case .zero: - return String(format: self._Forward_ConfirmMultipleFiles_zero, "\(value)") - case .one: - return String(format: self._Forward_ConfirmMultipleFiles_one, "\(value)") - case .two: - return String(format: self._Forward_ConfirmMultipleFiles_two, "\(value)") - case .few: - return String(format: self._Forward_ConfirmMultipleFiles_few, "\(value)") - case .many: - return String(format: self._Forward_ConfirmMultipleFiles_many, "\(value)") - case .other: - return String(format: self._Forward_ConfirmMultipleFiles_other, "\(value)") - } - } - private let _SharedMedia_Video_zero: String - private let _SharedMedia_Video_one: String - private let _SharedMedia_Video_two: String - private let _SharedMedia_Video_few: String - private let _SharedMedia_Video_many: String - private let _SharedMedia_Video_other: String - public func SharedMedia_Video(_ value: Int32) -> String { - switch presentationStringsPluralizationForm(self.lc, value) { - case .zero: - return String(format: self._SharedMedia_Video_zero, "\(value)") - case .one: - return String(format: self._SharedMedia_Video_one, "\(value)") - case .two: - return String(format: self._SharedMedia_Video_two, "\(value)") - case .few: - return String(format: self._SharedMedia_Video_few, "\(value)") - case .many: - return String(format: self._SharedMedia_Video_many, "\(value)") - case .other: - return String(format: self._SharedMedia_Video_other, "\(value)") - } - } - private let _Call_ShortSeconds_zero: String - private let _Call_ShortSeconds_one: String - private let _Call_ShortSeconds_two: String - private let _Call_ShortSeconds_few: String - private let _Call_ShortSeconds_many: String - private let _Call_ShortSeconds_other: String - public func Call_ShortSeconds(_ value: Int32) -> String { - switch presentationStringsPluralizationForm(self.lc, value) { - case .zero: - return String(format: self._Call_ShortSeconds_zero, "\(value)") - case .one: - return String(format: self._Call_ShortSeconds_one, "\(value)") - case .two: - return String(format: self._Call_ShortSeconds_two, "\(value)") - case .few: - return String(format: self._Call_ShortSeconds_few, "\(value)") - case .many: - return String(format: self._Call_ShortSeconds_many, "\(value)") - case .other: - return String(format: self._Call_ShortSeconds_other, "\(value)") - } - } - private let _LiveLocationUpdated_MinutesAgo_zero: String - private let _LiveLocationUpdated_MinutesAgo_one: String - private let _LiveLocationUpdated_MinutesAgo_two: String - private let _LiveLocationUpdated_MinutesAgo_few: String - private let _LiveLocationUpdated_MinutesAgo_many: String - private let _LiveLocationUpdated_MinutesAgo_other: String - public func LiveLocationUpdated_MinutesAgo(_ value: Int32) -> String { - switch presentationStringsPluralizationForm(self.lc, value) { - case .zero: - return String(format: self._LiveLocationUpdated_MinutesAgo_zero, "\(value)") - case .one: - return String(format: self._LiveLocationUpdated_MinutesAgo_one, "\(value)") - case .two: - return String(format: self._LiveLocationUpdated_MinutesAgo_two, "\(value)") - case .few: - return String(format: self._LiveLocationUpdated_MinutesAgo_few, "\(value)") - case .many: - return String(format: self._LiveLocationUpdated_MinutesAgo_many, "\(value)") - case .other: - return String(format: self._LiveLocationUpdated_MinutesAgo_other, "\(value)") - } - } - private let _MuteExpires_Hours_zero: String - private let _MuteExpires_Hours_one: String - private let _MuteExpires_Hours_two: String - private let _MuteExpires_Hours_few: String - private let _MuteExpires_Hours_many: String - private let _MuteExpires_Hours_other: String - public func MuteExpires_Hours(_ value: Int32) -> String { - switch presentationStringsPluralizationForm(self.lc, value) { - case .zero: - return String(format: self._MuteExpires_Hours_zero, "\(value)") - case .one: - return String(format: self._MuteExpires_Hours_one, "\(value)") - case .two: - return String(format: self._MuteExpires_Hours_two, "\(value)") - case .few: - return String(format: self._MuteExpires_Hours_few, "\(value)") - case .many: - return String(format: self._MuteExpires_Hours_many, "\(value)") - case .other: - return String(format: self._MuteExpires_Hours_other, "\(value)") - } - } - private let _SharedMedia_DeleteItemsConfirmation_zero: String - private let _SharedMedia_DeleteItemsConfirmation_one: String - private let _SharedMedia_DeleteItemsConfirmation_two: String - private let _SharedMedia_DeleteItemsConfirmation_few: String - private let _SharedMedia_DeleteItemsConfirmation_many: String - private let _SharedMedia_DeleteItemsConfirmation_other: String - public func SharedMedia_DeleteItemsConfirmation(_ value: Int32) -> String { - switch presentationStringsPluralizationForm(self.lc, value) { - case .zero: - return String(format: self._SharedMedia_DeleteItemsConfirmation_zero, "\(value)") - case .one: - return String(format: self._SharedMedia_DeleteItemsConfirmation_one, "\(value)") - case .two: - return String(format: self._SharedMedia_DeleteItemsConfirmation_two, "\(value)") - case .few: - return String(format: self._SharedMedia_DeleteItemsConfirmation_few, "\(value)") - case .many: - return String(format: self._SharedMedia_DeleteItemsConfirmation_many, "\(value)") - case .other: - return String(format: self._SharedMedia_DeleteItemsConfirmation_other, "\(value)") - } - } - private let _Conversation_StatusMembers_zero: String - private let _Conversation_StatusMembers_one: String - private let _Conversation_StatusMembers_two: String - private let _Conversation_StatusMembers_few: String - private let _Conversation_StatusMembers_many: String - private let _Conversation_StatusMembers_other: String - public func Conversation_StatusMembers(_ value: Int32) -> String { - switch presentationStringsPluralizationForm(self.lc, value) { - case .zero: - return String(format: self._Conversation_StatusMembers_zero, "\(value)") - case .one: - return String(format: self._Conversation_StatusMembers_one, "\(value)") - case .two: - return String(format: self._Conversation_StatusMembers_two, "\(value)") - case .few: - return String(format: self._Conversation_StatusMembers_few, "\(value)") - case .many: - return String(format: self._Conversation_StatusMembers_many, "\(value)") - case .other: - return String(format: self._Conversation_StatusMembers_other, "\(value)") - } - } - private let _MessageTimer_Seconds_zero: String - private let _MessageTimer_Seconds_one: String - private let _MessageTimer_Seconds_two: String - private let _MessageTimer_Seconds_few: String - private let _MessageTimer_Seconds_many: String - private let _MessageTimer_Seconds_other: String - public func MessageTimer_Seconds(_ value: Int32) -> String { - switch presentationStringsPluralizationForm(self.lc, value) { - case .zero: - return String(format: self._MessageTimer_Seconds_zero, "\(value)") - case .one: - return String(format: self._MessageTimer_Seconds_one, "\(value)") - case .two: - return String(format: self._MessageTimer_Seconds_two, "\(value)") - case .few: - return String(format: self._MessageTimer_Seconds_few, "\(value)") - case .many: - return String(format: self._MessageTimer_Seconds_many, "\(value)") - case .other: - return String(format: self._MessageTimer_Seconds_other, "\(value)") - } - } - private let _Watch_LastSeen_MinutesAgo_zero: String - private let _Watch_LastSeen_MinutesAgo_one: String - private let _Watch_LastSeen_MinutesAgo_two: String - private let _Watch_LastSeen_MinutesAgo_few: String - private let _Watch_LastSeen_MinutesAgo_many: String - private let _Watch_LastSeen_MinutesAgo_other: String - public func Watch_LastSeen_MinutesAgo(_ value: Int32) -> String { - switch presentationStringsPluralizationForm(self.lc, value) { - case .zero: - return String(format: self._Watch_LastSeen_MinutesAgo_zero, "\(value)") - case .one: - return String(format: self._Watch_LastSeen_MinutesAgo_one, "\(value)") - case .two: - return String(format: self._Watch_LastSeen_MinutesAgo_two, "\(value)") - case .few: - return String(format: self._Watch_LastSeen_MinutesAgo_few, "\(value)") - case .many: - return String(format: self._Watch_LastSeen_MinutesAgo_many, "\(value)") - case .other: - return String(format: self._Watch_LastSeen_MinutesAgo_other, "\(value)") - } - } - private let _LastSeen_HoursAgo_zero: String - private let _LastSeen_HoursAgo_one: String - private let _LastSeen_HoursAgo_two: String - private let _LastSeen_HoursAgo_few: String - private let _LastSeen_HoursAgo_many: String - private let _LastSeen_HoursAgo_other: String - public func LastSeen_HoursAgo(_ value: Int32) -> String { - switch presentationStringsPluralizationForm(self.lc, value) { - case .zero: - return String(format: self._LastSeen_HoursAgo_zero, "\(value)") - case .one: - return String(format: self._LastSeen_HoursAgo_one, "\(value)") - case .two: - return String(format: self._LastSeen_HoursAgo_two, "\(value)") - case .few: - return String(format: self._LastSeen_HoursAgo_few, "\(value)") - case .many: - return String(format: self._LastSeen_HoursAgo_many, "\(value)") - case .other: - return String(format: self._LastSeen_HoursAgo_other, "\(value)") - } - } - private let _Media_ShareItem_zero: String - private let _Media_ShareItem_one: String - private let _Media_ShareItem_two: String - private let _Media_ShareItem_few: String - private let _Media_ShareItem_many: String - private let _Media_ShareItem_other: String - public func Media_ShareItem(_ value: Int32) -> String { - switch presentationStringsPluralizationForm(self.lc, value) { - case .zero: - return String(format: self._Media_ShareItem_zero, "\(value)") - case .one: - return String(format: self._Media_ShareItem_one, "\(value)") - case .two: - return String(format: self._Media_ShareItem_two, "\(value)") - case .few: - return String(format: self._Media_ShareItem_few, "\(value)") - case .many: - return String(format: self._Media_ShareItem_many, "\(value)") - case .other: - return String(format: self._Media_ShareItem_other, "\(value)") - } - } - private let _QuickSend_Photos_zero: String - private let _QuickSend_Photos_one: String - private let _QuickSend_Photos_two: String - private let _QuickSend_Photos_few: String - private let _QuickSend_Photos_many: String - private let _QuickSend_Photos_other: String - public func QuickSend_Photos(_ value: Int32) -> String { - switch presentationStringsPluralizationForm(self.lc, value) { - case .zero: - return String(format: self._QuickSend_Photos_zero, "\(value)") - case .one: - return String(format: self._QuickSend_Photos_one, "\(value)") - case .two: - return String(format: self._QuickSend_Photos_two, "\(value)") - case .few: - return String(format: self._QuickSend_Photos_few, "\(value)") - case .many: - return String(format: self._QuickSend_Photos_many, "\(value)") - case .other: - return String(format: self._QuickSend_Photos_other, "\(value)") - } - } - private let _Media_SharePhoto_zero: String - private let _Media_SharePhoto_one: String - private let _Media_SharePhoto_two: String - private let _Media_SharePhoto_few: String - private let _Media_SharePhoto_many: String - private let _Media_SharePhoto_other: String - public func Media_SharePhoto(_ value: Int32) -> String { - switch presentationStringsPluralizationForm(self.lc, value) { - case .zero: - return String(format: self._Media_SharePhoto_zero, "\(value)") - case .one: - return String(format: self._Media_SharePhoto_one, "\(value)") - case .two: - return String(format: self._Media_SharePhoto_two, "\(value)") - case .few: - return String(format: self._Media_SharePhoto_few, "\(value)") - case .many: - return String(format: self._Media_SharePhoto_many, "\(value)") - case .other: - return String(format: self._Media_SharePhoto_other, "\(value)") - } - } - private let _MuteExpires_Minutes_zero: String - private let _MuteExpires_Minutes_one: String - private let _MuteExpires_Minutes_two: String - private let _MuteExpires_Minutes_few: String - private let _MuteExpires_Minutes_many: String - private let _MuteExpires_Minutes_other: String - public func MuteExpires_Minutes(_ value: Int32) -> String { - switch presentationStringsPluralizationForm(self.lc, value) { - case .zero: - return String(format: self._MuteExpires_Minutes_zero, "\(value)") - case .one: - return String(format: self._MuteExpires_Minutes_one, "\(value)") - case .two: - return String(format: self._MuteExpires_Minutes_two, "\(value)") - case .few: - return String(format: self._MuteExpires_Minutes_few, "\(value)") - case .many: - return String(format: self._MuteExpires_Minutes_many, "\(value)") - case .other: - return String(format: self._MuteExpires_Minutes_other, "\(value)") - } - } - private let _Notification_GameScoreSimple_zero: String - private let _Notification_GameScoreSimple_one: String - private let _Notification_GameScoreSimple_two: String - private let _Notification_GameScoreSimple_few: String - private let _Notification_GameScoreSimple_many: String - private let _Notification_GameScoreSimple_other: String - public func Notification_GameScoreSimple(_ value: Int32) -> String { - switch presentationStringsPluralizationForm(self.lc, value) { - case .zero: - return String(format: self._Notification_GameScoreSimple_zero, "\(value)") - case .one: - return String(format: self._Notification_GameScoreSimple_one, "\(value)") - case .two: - return String(format: self._Notification_GameScoreSimple_two, "\(value)") - case .few: - return String(format: self._Notification_GameScoreSimple_few, "\(value)") - case .many: - return String(format: self._Notification_GameScoreSimple_many, "\(value)") - case .other: - return String(format: self._Notification_GameScoreSimple_other, "\(value)") - } - } - private let _AttachmentMenu_SendItem_zero: String - private let _AttachmentMenu_SendItem_one: String - private let _AttachmentMenu_SendItem_two: String - private let _AttachmentMenu_SendItem_few: String - private let _AttachmentMenu_SendItem_many: String - private let _AttachmentMenu_SendItem_other: String - public func AttachmentMenu_SendItem(_ value: Int32) -> String { - switch presentationStringsPluralizationForm(self.lc, value) { - case .zero: - return String(format: self._AttachmentMenu_SendItem_zero, "\(value)") - case .one: - return String(format: self._AttachmentMenu_SendItem_one, "\(value)") - case .two: - return String(format: self._AttachmentMenu_SendItem_two, "\(value)") - case .few: - return String(format: self._AttachmentMenu_SendItem_few, "\(value)") - case .many: - return String(format: self._AttachmentMenu_SendItem_many, "\(value)") - case .other: - return String(format: self._AttachmentMenu_SendItem_other, "\(value)") - } - } - private let _MessageTimer_Years_zero: String - private let _MessageTimer_Years_one: String - private let _MessageTimer_Years_two: String - private let _MessageTimer_Years_few: String - private let _MessageTimer_Years_many: String - private let _MessageTimer_Years_other: String - public func MessageTimer_Years(_ value: Int32) -> String { - switch presentationStringsPluralizationForm(self.lc, value) { - case .zero: - return String(format: self._MessageTimer_Years_zero, "\(value)") - case .one: - return String(format: self._MessageTimer_Years_one, "\(value)") - case .two: - return String(format: self._MessageTimer_Years_two, "\(value)") - case .few: - return String(format: self._MessageTimer_Years_few, "\(value)") - case .many: - return String(format: self._MessageTimer_Years_many, "\(value)") - case .other: - return String(format: self._MessageTimer_Years_other, "\(value)") - } - } - private let _PrivacyLastSeenSettings_AddUsers_zero: String - private let _PrivacyLastSeenSettings_AddUsers_one: String - private let _PrivacyLastSeenSettings_AddUsers_two: String - private let _PrivacyLastSeenSettings_AddUsers_few: String - private let _PrivacyLastSeenSettings_AddUsers_many: String - private let _PrivacyLastSeenSettings_AddUsers_other: String - public func PrivacyLastSeenSettings_AddUsers(_ value: Int32) -> String { - switch presentationStringsPluralizationForm(self.lc, value) { - case .zero: - return String(format: self._PrivacyLastSeenSettings_AddUsers_zero, "\(value)") - case .one: - return String(format: self._PrivacyLastSeenSettings_AddUsers_one, "\(value)") - case .two: - return String(format: self._PrivacyLastSeenSettings_AddUsers_two, "\(value)") - case .few: - return String(format: self._PrivacyLastSeenSettings_AddUsers_few, "\(value)") - case .many: - return String(format: self._PrivacyLastSeenSettings_AddUsers_many, "\(value)") - case .other: - return String(format: self._PrivacyLastSeenSettings_AddUsers_other, "\(value)") - } - } - private let _AttachmentMenu_SendGif_zero: String - private let _AttachmentMenu_SendGif_one: String - private let _AttachmentMenu_SendGif_two: String - private let _AttachmentMenu_SendGif_few: String - private let _AttachmentMenu_SendGif_many: String - private let _AttachmentMenu_SendGif_other: String - public func AttachmentMenu_SendGif(_ value: Int32) -> String { - switch presentationStringsPluralizationForm(self.lc, value) { - case .zero: - return String(format: self._AttachmentMenu_SendGif_zero, "\(value)") - case .one: - return String(format: self._AttachmentMenu_SendGif_one, "\(value)") - case .two: - return String(format: self._AttachmentMenu_SendGif_two, "\(value)") - case .few: - return String(format: self._AttachmentMenu_SendGif_few, "\(value)") - case .many: - return String(format: self._AttachmentMenu_SendGif_many, "\(value)") - case .other: - return String(format: self._AttachmentMenu_SendGif_other, "\(value)") - } - } - private let _ForwardedVideoMessages_zero: String - private let _ForwardedVideoMessages_one: String - private let _ForwardedVideoMessages_two: String - private let _ForwardedVideoMessages_few: String - private let _ForwardedVideoMessages_many: String - private let _ForwardedVideoMessages_other: String - public func ForwardedVideoMessages(_ value: Int32) -> String { - switch presentationStringsPluralizationForm(self.lc, value) { - case .zero: - return String(format: self._ForwardedVideoMessages_zero, "\(value)") - case .one: - return String(format: self._ForwardedVideoMessages_one, "\(value)") - case .two: - return String(format: self._ForwardedVideoMessages_two, "\(value)") - case .few: - return String(format: self._ForwardedVideoMessages_few, "\(value)") - case .many: - return String(format: self._ForwardedVideoMessages_many, "\(value)") - case .other: - return String(format: self._ForwardedVideoMessages_other, "\(value)") - } - } - private let _Media_ShareVideo_zero: String - private let _Media_ShareVideo_one: String - private let _Media_ShareVideo_two: String - private let _Media_ShareVideo_few: String - private let _Media_ShareVideo_many: String - private let _Media_ShareVideo_other: String - public func Media_ShareVideo(_ value: Int32) -> String { - switch presentationStringsPluralizationForm(self.lc, value) { - case .zero: - return String(format: self._Media_ShareVideo_zero, "\(value)") - case .one: - return String(format: self._Media_ShareVideo_one, "\(value)") - case .two: - return String(format: self._Media_ShareVideo_two, "\(value)") - case .few: - return String(format: self._Media_ShareVideo_few, "\(value)") - case .many: - return String(format: self._Media_ShareVideo_many, "\(value)") - case .other: - return String(format: self._Media_ShareVideo_other, "\(value)") + return String(format: self._Notifications_Exceptions_other, "\(value)") } } private let _StickerPack_RemoveStickerCount_zero: String @@ -5011,94 +4314,6 @@ public final class PresentationStrings { return String(format: self._StickerPack_RemoveStickerCount_other, "\(value)") } } - private let _Call_Seconds_zero: String - private let _Call_Seconds_one: String - private let _Call_Seconds_two: String - private let _Call_Seconds_few: String - private let _Call_Seconds_many: String - private let _Call_Seconds_other: String - public func Call_Seconds(_ value: Int32) -> String { - switch presentationStringsPluralizationForm(self.lc, value) { - case .zero: - return String(format: self._Call_Seconds_zero, "\(value)") - case .one: - return String(format: self._Call_Seconds_one, "\(value)") - case .two: - return String(format: self._Call_Seconds_two, "\(value)") - case .few: - return String(format: self._Call_Seconds_few, "\(value)") - case .many: - return String(format: self._Call_Seconds_many, "\(value)") - case .other: - return String(format: self._Call_Seconds_other, "\(value)") - } - } - private let _MessageTimer_Hours_zero: String - private let _MessageTimer_Hours_one: String - private let _MessageTimer_Hours_two: String - private let _MessageTimer_Hours_few: String - private let _MessageTimer_Hours_many: String - private let _MessageTimer_Hours_other: String - public func MessageTimer_Hours(_ value: Int32) -> String { - switch presentationStringsPluralizationForm(self.lc, value) { - case .zero: - return String(format: self._MessageTimer_Hours_zero, "\(value)") - case .one: - return String(format: self._MessageTimer_Hours_one, "\(value)") - case .two: - return String(format: self._MessageTimer_Hours_two, "\(value)") - case .few: - return String(format: self._MessageTimer_Hours_few, "\(value)") - case .many: - return String(format: self._MessageTimer_Hours_many, "\(value)") - case .other: - return String(format: self._MessageTimer_Hours_other, "\(value)") - } - } - private let _Conversation_StatusOnline_zero: String - private let _Conversation_StatusOnline_one: String - private let _Conversation_StatusOnline_two: String - private let _Conversation_StatusOnline_few: String - private let _Conversation_StatusOnline_many: String - private let _Conversation_StatusOnline_other: String - public func Conversation_StatusOnline(_ value: Int32) -> String { - switch presentationStringsPluralizationForm(self.lc, value) { - case .zero: - return String(format: self._Conversation_StatusOnline_zero, "\(value)") - case .one: - return String(format: self._Conversation_StatusOnline_one, "\(value)") - case .two: - return String(format: self._Conversation_StatusOnline_two, "\(value)") - case .few: - return String(format: self._Conversation_StatusOnline_few, "\(value)") - case .many: - return String(format: self._Conversation_StatusOnline_many, "\(value)") - case .other: - return String(format: self._Conversation_StatusOnline_other, "\(value)") - } - } - private let _ForwardedPhotos_zero: String - private let _ForwardedPhotos_one: String - private let _ForwardedPhotos_two: String - private let _ForwardedPhotos_few: String - private let _ForwardedPhotos_many: String - private let _ForwardedPhotos_other: String - public func ForwardedPhotos(_ value: Int32) -> String { - switch presentationStringsPluralizationForm(self.lc, value) { - case .zero: - return String(format: self._ForwardedPhotos_zero, "\(value)") - case .one: - return String(format: self._ForwardedPhotos_one, "\(value)") - case .two: - return String(format: self._ForwardedPhotos_two, "\(value)") - case .few: - return String(format: self._ForwardedPhotos_few, "\(value)") - case .many: - return String(format: self._ForwardedPhotos_many, "\(value)") - case .other: - return String(format: self._ForwardedPhotos_other, "\(value)") - } - } private let _MessageTimer_Weeks_zero: String private let _MessageTimer_Weeks_one: String private let _MessageTimer_Weeks_two: String @@ -5121,202 +4336,312 @@ public final class PresentationStrings { return String(format: self._MessageTimer_Weeks_other, "\(value)") } } - private let _Call_ShortMinutes_zero: String - private let _Call_ShortMinutes_one: String - private let _Call_ShortMinutes_two: String - private let _Call_ShortMinutes_few: String - private let _Call_ShortMinutes_many: String - private let _Call_ShortMinutes_other: String - public func Call_ShortMinutes(_ value: Int32) -> String { + private let _ForwardedContacts_zero: String + private let _ForwardedContacts_one: String + private let _ForwardedContacts_two: String + private let _ForwardedContacts_few: String + private let _ForwardedContacts_many: String + private let _ForwardedContacts_other: String + public func ForwardedContacts(_ value: Int32) -> String { switch presentationStringsPluralizationForm(self.lc, value) { case .zero: - return String(format: self._Call_ShortMinutes_zero, "\(value)") + return String(format: self._ForwardedContacts_zero, "\(value)") case .one: - return String(format: self._Call_ShortMinutes_one, "\(value)") + return String(format: self._ForwardedContacts_one, "\(value)") case .two: - return String(format: self._Call_ShortMinutes_two, "\(value)") + return String(format: self._ForwardedContacts_two, "\(value)") case .few: - return String(format: self._Call_ShortMinutes_few, "\(value)") + return String(format: self._ForwardedContacts_few, "\(value)") case .many: - return String(format: self._Call_ShortMinutes_many, "\(value)") + return String(format: self._ForwardedContacts_many, "\(value)") case .other: - return String(format: self._Call_ShortMinutes_other, "\(value)") + return String(format: self._ForwardedContacts_other, "\(value)") } } - private let _Notifications_ExceptionMuteExpires_Days_zero: String - private let _Notifications_ExceptionMuteExpires_Days_one: String - private let _Notifications_ExceptionMuteExpires_Days_two: String - private let _Notifications_ExceptionMuteExpires_Days_few: String - private let _Notifications_ExceptionMuteExpires_Days_many: String - private let _Notifications_ExceptionMuteExpires_Days_other: String - public func Notifications_ExceptionMuteExpires_Days(_ value: Int32) -> String { + private let _Media_ShareItem_zero: String + private let _Media_ShareItem_one: String + private let _Media_ShareItem_two: String + private let _Media_ShareItem_few: String + private let _Media_ShareItem_many: String + private let _Media_ShareItem_other: String + public func Media_ShareItem(_ value: Int32) -> String { switch presentationStringsPluralizationForm(self.lc, value) { case .zero: - return String(format: self._Notifications_ExceptionMuteExpires_Days_zero, "\(value)") + return String(format: self._Media_ShareItem_zero, "\(value)") case .one: - return String(format: self._Notifications_ExceptionMuteExpires_Days_one, "\(value)") + return String(format: self._Media_ShareItem_one, "\(value)") case .two: - return String(format: self._Notifications_ExceptionMuteExpires_Days_two, "\(value)") + return String(format: self._Media_ShareItem_two, "\(value)") case .few: - return String(format: self._Notifications_ExceptionMuteExpires_Days_few, "\(value)") + return String(format: self._Media_ShareItem_few, "\(value)") case .many: - return String(format: self._Notifications_ExceptionMuteExpires_Days_many, "\(value)") + return String(format: self._Media_ShareItem_many, "\(value)") case .other: - return String(format: self._Notifications_ExceptionMuteExpires_Days_other, "\(value)") + return String(format: self._Media_ShareItem_other, "\(value)") } } - private let _ForwardedAudios_zero: String - private let _ForwardedAudios_one: String - private let _ForwardedAudios_two: String - private let _ForwardedAudios_few: String - private let _ForwardedAudios_many: String - private let _ForwardedAudios_other: String - public func ForwardedAudios(_ value: Int32) -> String { + private let _MessageTimer_ShortDays_zero: String + private let _MessageTimer_ShortDays_one: String + private let _MessageTimer_ShortDays_two: String + private let _MessageTimer_ShortDays_few: String + private let _MessageTimer_ShortDays_many: String + private let _MessageTimer_ShortDays_other: String + public func MessageTimer_ShortDays(_ value: Int32) -> String { switch presentationStringsPluralizationForm(self.lc, value) { case .zero: - return String(format: self._ForwardedAudios_zero, "\(value)") + return String(format: self._MessageTimer_ShortDays_zero, "\(value)") case .one: - return String(format: self._ForwardedAudios_one, "\(value)") + return String(format: self._MessageTimer_ShortDays_one, "\(value)") case .two: - return String(format: self._ForwardedAudios_two, "\(value)") + return String(format: self._MessageTimer_ShortDays_two, "\(value)") case .few: - return String(format: self._ForwardedAudios_few, "\(value)") + return String(format: self._MessageTimer_ShortDays_few, "\(value)") case .many: - return String(format: self._ForwardedAudios_many, "\(value)") + return String(format: self._MessageTimer_ShortDays_many, "\(value)") case .other: - return String(format: self._ForwardedAudios_other, "\(value)") + return String(format: self._MessageTimer_ShortDays_other, "\(value)") } } - private let _Conversation_LiveLocationMembersCount_zero: String - private let _Conversation_LiveLocationMembersCount_one: String - private let _Conversation_LiveLocationMembersCount_two: String - private let _Conversation_LiveLocationMembersCount_few: String - private let _Conversation_LiveLocationMembersCount_many: String - private let _Conversation_LiveLocationMembersCount_other: String - public func Conversation_LiveLocationMembersCount(_ value: Int32) -> String { + private let _Forward_ConfirmMultipleFiles_zero: String + private let _Forward_ConfirmMultipleFiles_one: String + private let _Forward_ConfirmMultipleFiles_two: String + private let _Forward_ConfirmMultipleFiles_few: String + private let _Forward_ConfirmMultipleFiles_many: String + private let _Forward_ConfirmMultipleFiles_other: String + public func Forward_ConfirmMultipleFiles(_ value: Int32) -> String { switch presentationStringsPluralizationForm(self.lc, value) { case .zero: - return String(format: self._Conversation_LiveLocationMembersCount_zero, "\(value)") + return String(format: self._Forward_ConfirmMultipleFiles_zero, "\(value)") case .one: - return String(format: self._Conversation_LiveLocationMembersCount_one, "\(value)") + return String(format: self._Forward_ConfirmMultipleFiles_one, "\(value)") case .two: - return String(format: self._Conversation_LiveLocationMembersCount_two, "\(value)") + return String(format: self._Forward_ConfirmMultipleFiles_two, "\(value)") case .few: - return String(format: self._Conversation_LiveLocationMembersCount_few, "\(value)") + return String(format: self._Forward_ConfirmMultipleFiles_few, "\(value)") case .many: - return String(format: self._Conversation_LiveLocationMembersCount_many, "\(value)") + return String(format: self._Forward_ConfirmMultipleFiles_many, "\(value)") case .other: - return String(format: self._Conversation_LiveLocationMembersCount_other, "\(value)") + return String(format: self._Forward_ConfirmMultipleFiles_other, "\(value)") } } - private let _StickerPack_AddStickerCount_zero: String - private let _StickerPack_AddStickerCount_one: String - private let _StickerPack_AddStickerCount_two: String - private let _StickerPack_AddStickerCount_few: String - private let _StickerPack_AddStickerCount_many: String - private let _StickerPack_AddStickerCount_other: String - public func StickerPack_AddStickerCount(_ value: Int32) -> String { + private let _Map_ETAHours_zero: String + private let _Map_ETAHours_one: String + private let _Map_ETAHours_two: String + private let _Map_ETAHours_few: String + private let _Map_ETAHours_many: String + private let _Map_ETAHours_other: String + public func Map_ETAHours(_ value: Int32) -> String { switch presentationStringsPluralizationForm(self.lc, value) { case .zero: - return String(format: self._StickerPack_AddStickerCount_zero, "\(value)") + return String(format: self._Map_ETAHours_zero, "\(value)") case .one: - return String(format: self._StickerPack_AddStickerCount_one, "\(value)") + return String(format: self._Map_ETAHours_one, "\(value)") case .two: - return String(format: self._StickerPack_AddStickerCount_two, "\(value)") + return String(format: self._Map_ETAHours_two, "\(value)") case .few: - return String(format: self._StickerPack_AddStickerCount_few, "\(value)") + return String(format: self._Map_ETAHours_few, "\(value)") case .many: - return String(format: self._StickerPack_AddStickerCount_many, "\(value)") + return String(format: self._Map_ETAHours_many, "\(value)") case .other: - return String(format: self._StickerPack_AddStickerCount_other, "\(value)") + return String(format: self._Map_ETAHours_other, "\(value)") } } - private let _Contacts_ImportersCount_zero: String - private let _Contacts_ImportersCount_one: String - private let _Contacts_ImportersCount_two: String - private let _Contacts_ImportersCount_few: String - private let _Contacts_ImportersCount_many: String - private let _Contacts_ImportersCount_other: String - public func Contacts_ImportersCount(_ value: Int32) -> String { + private let _ServiceMessage_GameScoreExtended_zero: String + private let _ServiceMessage_GameScoreExtended_one: String + private let _ServiceMessage_GameScoreExtended_two: String + private let _ServiceMessage_GameScoreExtended_few: String + private let _ServiceMessage_GameScoreExtended_many: String + private let _ServiceMessage_GameScoreExtended_other: String + public func ServiceMessage_GameScoreExtended(_ value: Int32) -> String { switch presentationStringsPluralizationForm(self.lc, value) { case .zero: - return String(format: self._Contacts_ImportersCount_zero, "\(value)") + return String(format: self._ServiceMessage_GameScoreExtended_zero, "\(value)") case .one: - return String(format: self._Contacts_ImportersCount_one, "\(value)") + return String(format: self._ServiceMessage_GameScoreExtended_one, "\(value)") case .two: - return String(format: self._Contacts_ImportersCount_two, "\(value)") + return String(format: self._ServiceMessage_GameScoreExtended_two, "\(value)") case .few: - return String(format: self._Contacts_ImportersCount_few, "\(value)") + return String(format: self._ServiceMessage_GameScoreExtended_few, "\(value)") case .many: - return String(format: self._Contacts_ImportersCount_many, "\(value)") + return String(format: self._ServiceMessage_GameScoreExtended_many, "\(value)") case .other: - return String(format: self._Contacts_ImportersCount_other, "\(value)") + return String(format: self._ServiceMessage_GameScoreExtended_other, "\(value)") } } - private let _StickerPack_RemoveMaskCount_zero: String - private let _StickerPack_RemoveMaskCount_one: String - private let _StickerPack_RemoveMaskCount_two: String - private let _StickerPack_RemoveMaskCount_few: String - private let _StickerPack_RemoveMaskCount_many: String - private let _StickerPack_RemoveMaskCount_other: String - public func StickerPack_RemoveMaskCount(_ value: Int32) -> String { + private let _ForwardedGifs_zero: String + private let _ForwardedGifs_one: String + private let _ForwardedGifs_two: String + private let _ForwardedGifs_few: String + private let _ForwardedGifs_many: String + private let _ForwardedGifs_other: String + public func ForwardedGifs(_ value: Int32) -> String { switch presentationStringsPluralizationForm(self.lc, value) { case .zero: - return String(format: self._StickerPack_RemoveMaskCount_zero, "\(value)") + return String(format: self._ForwardedGifs_zero, "\(value)") case .one: - return String(format: self._StickerPack_RemoveMaskCount_one, "\(value)") + return String(format: self._ForwardedGifs_one, "\(value)") case .two: - return String(format: self._StickerPack_RemoveMaskCount_two, "\(value)") + return String(format: self._ForwardedGifs_two, "\(value)") case .few: - return String(format: self._StickerPack_RemoveMaskCount_few, "\(value)") + return String(format: self._ForwardedGifs_few, "\(value)") case .many: - return String(format: self._StickerPack_RemoveMaskCount_many, "\(value)") + return String(format: self._ForwardedGifs_many, "\(value)") case .other: - return String(format: self._StickerPack_RemoveMaskCount_other, "\(value)") + return String(format: self._ForwardedGifs_other, "\(value)") } } - private let _Notifications_ExceptionMuteExpires_Minutes_zero: String - private let _Notifications_ExceptionMuteExpires_Minutes_one: String - private let _Notifications_ExceptionMuteExpires_Minutes_two: String - private let _Notifications_ExceptionMuteExpires_Minutes_few: String - private let _Notifications_ExceptionMuteExpires_Minutes_many: String - private let _Notifications_ExceptionMuteExpires_Minutes_other: String - public func Notifications_ExceptionMuteExpires_Minutes(_ value: Int32) -> String { + private let _Media_ShareVideo_zero: String + private let _Media_ShareVideo_one: String + private let _Media_ShareVideo_two: String + private let _Media_ShareVideo_few: String + private let _Media_ShareVideo_many: String + private let _Media_ShareVideo_other: String + public func Media_ShareVideo(_ value: Int32) -> String { switch presentationStringsPluralizationForm(self.lc, value) { case .zero: - return String(format: self._Notifications_ExceptionMuteExpires_Minutes_zero, "\(value)") + return String(format: self._Media_ShareVideo_zero, "\(value)") case .one: - return String(format: self._Notifications_ExceptionMuteExpires_Minutes_one, "\(value)") + return String(format: self._Media_ShareVideo_one, "\(value)") case .two: - return String(format: self._Notifications_ExceptionMuteExpires_Minutes_two, "\(value)") + return String(format: self._Media_ShareVideo_two, "\(value)") case .few: - return String(format: self._Notifications_ExceptionMuteExpires_Minutes_few, "\(value)") + return String(format: self._Media_ShareVideo_few, "\(value)") case .many: - return String(format: self._Notifications_ExceptionMuteExpires_Minutes_many, "\(value)") + return String(format: self._Media_ShareVideo_many, "\(value)") case .other: - return String(format: self._Notifications_ExceptionMuteExpires_Minutes_other, "\(value)") + return String(format: self._Media_ShareVideo_other, "\(value)") } } - private let _InviteText_ContactsCount_zero: String - private let _InviteText_ContactsCount_one: String - private let _InviteText_ContactsCount_two: String - private let _InviteText_ContactsCount_few: String - private let _InviteText_ContactsCount_many: String - private let _InviteText_ContactsCount_other: String - public func InviteText_ContactsCount(_ value: Int32) -> String { + private let _SharedMedia_Video_zero: String + private let _SharedMedia_Video_one: String + private let _SharedMedia_Video_two: String + private let _SharedMedia_Video_few: String + private let _SharedMedia_Video_many: String + private let _SharedMedia_Video_other: String + public func SharedMedia_Video(_ value: Int32) -> String { switch presentationStringsPluralizationForm(self.lc, value) { case .zero: - return String(format: self._InviteText_ContactsCount_zero, "\(value)") + return String(format: self._SharedMedia_Video_zero, "\(value)") case .one: - return String(format: self._InviteText_ContactsCount_one, "\(value)") + return String(format: self._SharedMedia_Video_one, "\(value)") case .two: - return String(format: self._InviteText_ContactsCount_two, "\(value)") + return String(format: self._SharedMedia_Video_two, "\(value)") case .few: - return String(format: self._InviteText_ContactsCount_few, "\(value)") + return String(format: self._SharedMedia_Video_few, "\(value)") case .many: - return String(format: self._InviteText_ContactsCount_many, "\(value)") + return String(format: self._SharedMedia_Video_many, "\(value)") case .other: - return String(format: self._InviteText_ContactsCount_other, "\(value)") + return String(format: self._SharedMedia_Video_other, "\(value)") + } + } + private let _PasscodeSettings_FailedAttempts_zero: String + private let _PasscodeSettings_FailedAttempts_one: String + private let _PasscodeSettings_FailedAttempts_two: String + private let _PasscodeSettings_FailedAttempts_few: String + private let _PasscodeSettings_FailedAttempts_many: String + private let _PasscodeSettings_FailedAttempts_other: String + public func PasscodeSettings_FailedAttempts(_ value: Int32) -> String { + switch presentationStringsPluralizationForm(self.lc, value) { + case .zero: + return String(format: self._PasscodeSettings_FailedAttempts_zero, "\(value)") + case .one: + return String(format: self._PasscodeSettings_FailedAttempts_one, "\(value)") + case .two: + return String(format: self._PasscodeSettings_FailedAttempts_two, "\(value)") + case .few: + return String(format: self._PasscodeSettings_FailedAttempts_few, "\(value)") + case .many: + return String(format: self._PasscodeSettings_FailedAttempts_many, "\(value)") + case .other: + return String(format: self._PasscodeSettings_FailedAttempts_other, "\(value)") + } + } + private let _QuickSend_Photos_zero: String + private let _QuickSend_Photos_one: String + private let _QuickSend_Photos_two: String + private let _QuickSend_Photos_few: String + private let _QuickSend_Photos_many: String + private let _QuickSend_Photos_other: String + public func QuickSend_Photos(_ value: Int32) -> String { + switch presentationStringsPluralizationForm(self.lc, value) { + case .zero: + return String(format: self._QuickSend_Photos_zero, "\(value)") + case .one: + return String(format: self._QuickSend_Photos_one, "\(value)") + case .two: + return String(format: self._QuickSend_Photos_two, "\(value)") + case .few: + return String(format: self._QuickSend_Photos_few, "\(value)") + case .many: + return String(format: self._QuickSend_Photos_many, "\(value)") + case .other: + return String(format: self._QuickSend_Photos_other, "\(value)") + } + } + private let _Watch_LastSeen_HoursAgo_zero: String + private let _Watch_LastSeen_HoursAgo_one: String + private let _Watch_LastSeen_HoursAgo_two: String + private let _Watch_LastSeen_HoursAgo_few: String + private let _Watch_LastSeen_HoursAgo_many: String + private let _Watch_LastSeen_HoursAgo_other: String + public func Watch_LastSeen_HoursAgo(_ value: Int32) -> String { + switch presentationStringsPluralizationForm(self.lc, value) { + case .zero: + return String(format: self._Watch_LastSeen_HoursAgo_zero, "\(value)") + case .one: + return String(format: self._Watch_LastSeen_HoursAgo_one, "\(value)") + case .two: + return String(format: self._Watch_LastSeen_HoursAgo_two, "\(value)") + case .few: + return String(format: self._Watch_LastSeen_HoursAgo_few, "\(value)") + case .many: + return String(format: self._Watch_LastSeen_HoursAgo_many, "\(value)") + case .other: + return String(format: self._Watch_LastSeen_HoursAgo_other, "\(value)") + } + } + private let _AttachmentMenu_SendGif_zero: String + private let _AttachmentMenu_SendGif_one: String + private let _AttachmentMenu_SendGif_two: String + private let _AttachmentMenu_SendGif_few: String + private let _AttachmentMenu_SendGif_many: String + private let _AttachmentMenu_SendGif_other: String + public func AttachmentMenu_SendGif(_ value: Int32) -> String { + switch presentationStringsPluralizationForm(self.lc, value) { + case .zero: + return String(format: self._AttachmentMenu_SendGif_zero, "\(value)") + case .one: + return String(format: self._AttachmentMenu_SendGif_one, "\(value)") + case .two: + return String(format: self._AttachmentMenu_SendGif_two, "\(value)") + case .few: + return String(format: self._AttachmentMenu_SendGif_few, "\(value)") + case .many: + return String(format: self._AttachmentMenu_SendGif_many, "\(value)") + case .other: + return String(format: self._AttachmentMenu_SendGif_other, "\(value)") + } + } + private let _Conversation_StatusSubscribers_zero: String + private let _Conversation_StatusSubscribers_one: String + private let _Conversation_StatusSubscribers_two: String + private let _Conversation_StatusSubscribers_few: String + private let _Conversation_StatusSubscribers_many: String + private let _Conversation_StatusSubscribers_other: String + public func Conversation_StatusSubscribers(_ value: Int32) -> String { + switch presentationStringsPluralizationForm(self.lc, value) { + case .zero: + return String(format: self._Conversation_StatusSubscribers_zero, "\(value)") + case .one: + return String(format: self._Conversation_StatusSubscribers_one, "\(value)") + case .two: + return String(format: self._Conversation_StatusSubscribers_two, "\(value)") + case .few: + return String(format: self._Conversation_StatusSubscribers_few, "\(value)") + case .many: + return String(format: self._Conversation_StatusSubscribers_many, "\(value)") + case .other: + return String(format: self._Conversation_StatusSubscribers_other, "\(value)") } } private let _SharedMedia_Link_zero: String @@ -5341,26 +4666,136 @@ public final class PresentationStrings { return String(format: self._SharedMedia_Link_other, "\(value)") } } - private let _Map_ETAMinutes_zero: String - private let _Map_ETAMinutes_one: String - private let _Map_ETAMinutes_two: String - private let _Map_ETAMinutes_few: String - private let _Map_ETAMinutes_many: String - private let _Map_ETAMinutes_other: String - public func Map_ETAMinutes(_ value: Int32) -> String { + private let _PrivacyLastSeenSettings_AddUsers_zero: String + private let _PrivacyLastSeenSettings_AddUsers_one: String + private let _PrivacyLastSeenSettings_AddUsers_two: String + private let _PrivacyLastSeenSettings_AddUsers_few: String + private let _PrivacyLastSeenSettings_AddUsers_many: String + private let _PrivacyLastSeenSettings_AddUsers_other: String + public func PrivacyLastSeenSettings_AddUsers(_ value: Int32) -> String { switch presentationStringsPluralizationForm(self.lc, value) { case .zero: - return String(format: self._Map_ETAMinutes_zero, "\(value)") + return String(format: self._PrivacyLastSeenSettings_AddUsers_zero, "\(value)") case .one: - return String(format: self._Map_ETAMinutes_one, "\(value)") + return String(format: self._PrivacyLastSeenSettings_AddUsers_one, "\(value)") case .two: - return String(format: self._Map_ETAMinutes_two, "\(value)") + return String(format: self._PrivacyLastSeenSettings_AddUsers_two, "\(value)") case .few: - return String(format: self._Map_ETAMinutes_few, "\(value)") + return String(format: self._PrivacyLastSeenSettings_AddUsers_few, "\(value)") case .many: - return String(format: self._Map_ETAMinutes_many, "\(value)") + return String(format: self._PrivacyLastSeenSettings_AddUsers_many, "\(value)") case .other: - return String(format: self._Map_ETAMinutes_other, "\(value)") + return String(format: self._PrivacyLastSeenSettings_AddUsers_other, "\(value)") + } + } + private let _ForwardedVideoMessages_zero: String + private let _ForwardedVideoMessages_one: String + private let _ForwardedVideoMessages_two: String + private let _ForwardedVideoMessages_few: String + private let _ForwardedVideoMessages_many: String + private let _ForwardedVideoMessages_other: String + public func ForwardedVideoMessages(_ value: Int32) -> String { + switch presentationStringsPluralizationForm(self.lc, value) { + case .zero: + return String(format: self._ForwardedVideoMessages_zero, "\(value)") + case .one: + return String(format: self._ForwardedVideoMessages_one, "\(value)") + case .two: + return String(format: self._ForwardedVideoMessages_two, "\(value)") + case .few: + return String(format: self._ForwardedVideoMessages_few, "\(value)") + case .many: + return String(format: self._ForwardedVideoMessages_many, "\(value)") + case .other: + return String(format: self._ForwardedVideoMessages_other, "\(value)") + } + } + private let _ForwardedMessages_zero: String + private let _ForwardedMessages_one: String + private let _ForwardedMessages_two: String + private let _ForwardedMessages_few: String + private let _ForwardedMessages_many: String + private let _ForwardedMessages_other: String + public func ForwardedMessages(_ value: Int32) -> String { + switch presentationStringsPluralizationForm(self.lc, value) { + case .zero: + return String(format: self._ForwardedMessages_zero, "\(value)") + case .one: + return String(format: self._ForwardedMessages_one, "\(value)") + case .two: + return String(format: self._ForwardedMessages_two, "\(value)") + case .few: + return String(format: self._ForwardedMessages_few, "\(value)") + case .many: + return String(format: self._ForwardedMessages_many, "\(value)") + case .other: + return String(format: self._ForwardedMessages_other, "\(value)") + } + } + private let _MessageTimer_Days_zero: String + private let _MessageTimer_Days_one: String + private let _MessageTimer_Days_two: String + private let _MessageTimer_Days_few: String + private let _MessageTimer_Days_many: String + private let _MessageTimer_Days_other: String + public func MessageTimer_Days(_ value: Int32) -> String { + switch presentationStringsPluralizationForm(self.lc, value) { + case .zero: + return String(format: self._MessageTimer_Days_zero, "\(value)") + case .one: + return String(format: self._MessageTimer_Days_one, "\(value)") + case .two: + return String(format: self._MessageTimer_Days_two, "\(value)") + case .few: + return String(format: self._MessageTimer_Days_few, "\(value)") + case .many: + return String(format: self._MessageTimer_Days_many, "\(value)") + case .other: + return String(format: self._MessageTimer_Days_other, "\(value)") + } + } + private let _Call_ShortMinutes_zero: String + private let _Call_ShortMinutes_one: String + private let _Call_ShortMinutes_two: String + private let _Call_ShortMinutes_few: String + private let _Call_ShortMinutes_many: String + private let _Call_ShortMinutes_other: String + public func Call_ShortMinutes(_ value: Int32) -> String { + switch presentationStringsPluralizationForm(self.lc, value) { + case .zero: + return String(format: self._Call_ShortMinutes_zero, "\(value)") + case .one: + return String(format: self._Call_ShortMinutes_one, "\(value)") + case .two: + return String(format: self._Call_ShortMinutes_two, "\(value)") + case .few: + return String(format: self._Call_ShortMinutes_few, "\(value)") + case .many: + return String(format: self._Call_ShortMinutes_many, "\(value)") + case .other: + return String(format: self._Call_ShortMinutes_other, "\(value)") + } + } + private let _AttachmentMenu_SendVideo_zero: String + private let _AttachmentMenu_SendVideo_one: String + private let _AttachmentMenu_SendVideo_two: String + private let _AttachmentMenu_SendVideo_few: String + private let _AttachmentMenu_SendVideo_many: String + private let _AttachmentMenu_SendVideo_other: String + public func AttachmentMenu_SendVideo(_ value: Int32) -> String { + switch presentationStringsPluralizationForm(self.lc, value) { + case .zero: + return String(format: self._AttachmentMenu_SendVideo_zero, "\(value)") + case .one: + return String(format: self._AttachmentMenu_SendVideo_one, "\(value)") + case .two: + return String(format: self._AttachmentMenu_SendVideo_two, "\(value)") + case .few: + return String(format: self._AttachmentMenu_SendVideo_few, "\(value)") + case .many: + return String(format: self._AttachmentMenu_SendVideo_many, "\(value)") + case .other: + return String(format: self._AttachmentMenu_SendVideo_other, "\(value)") } } private let _MessageTimer_Minutes_zero: String @@ -5385,48 +4820,180 @@ public final class PresentationStrings { return String(format: self._MessageTimer_Minutes_other, "\(value)") } } - private let _AttachmentMenu_SendPhoto_zero: String - private let _AttachmentMenu_SendPhoto_one: String - private let _AttachmentMenu_SendPhoto_two: String - private let _AttachmentMenu_SendPhoto_few: String - private let _AttachmentMenu_SendPhoto_many: String - private let _AttachmentMenu_SendPhoto_other: String - public func AttachmentMenu_SendPhoto(_ value: Int32) -> String { + private let _MessageTimer_Months_zero: String + private let _MessageTimer_Months_one: String + private let _MessageTimer_Months_two: String + private let _MessageTimer_Months_few: String + private let _MessageTimer_Months_many: String + private let _MessageTimer_Months_other: String + public func MessageTimer_Months(_ value: Int32) -> String { switch presentationStringsPluralizationForm(self.lc, value) { case .zero: - return String(format: self._AttachmentMenu_SendPhoto_zero, "\(value)") + return String(format: self._MessageTimer_Months_zero, "\(value)") case .one: - return String(format: self._AttachmentMenu_SendPhoto_one, "\(value)") + return String(format: self._MessageTimer_Months_one, "\(value)") case .two: - return String(format: self._AttachmentMenu_SendPhoto_two, "\(value)") + return String(format: self._MessageTimer_Months_two, "\(value)") case .few: - return String(format: self._AttachmentMenu_SendPhoto_few, "\(value)") + return String(format: self._MessageTimer_Months_few, "\(value)") case .many: - return String(format: self._AttachmentMenu_SendPhoto_many, "\(value)") + return String(format: self._MessageTimer_Months_many, "\(value)") case .other: - return String(format: self._AttachmentMenu_SendPhoto_other, "\(value)") + return String(format: self._MessageTimer_Months_other, "\(value)") } } - private let _Notifications_ExceptionMuteExpires_Hours_zero: String - private let _Notifications_ExceptionMuteExpires_Hours_one: String - private let _Notifications_ExceptionMuteExpires_Hours_two: String - private let _Notifications_ExceptionMuteExpires_Hours_few: String - private let _Notifications_ExceptionMuteExpires_Hours_many: String - private let _Notifications_ExceptionMuteExpires_Hours_other: String - public func Notifications_ExceptionMuteExpires_Hours(_ value: Int32) -> String { + private let _ServiceMessage_GameScoreSelfExtended_zero: String + private let _ServiceMessage_GameScoreSelfExtended_one: String + private let _ServiceMessage_GameScoreSelfExtended_two: String + private let _ServiceMessage_GameScoreSelfExtended_few: String + private let _ServiceMessage_GameScoreSelfExtended_many: String + private let _ServiceMessage_GameScoreSelfExtended_other: String + public func ServiceMessage_GameScoreSelfExtended(_ value: Int32) -> String { switch presentationStringsPluralizationForm(self.lc, value) { case .zero: - return String(format: self._Notifications_ExceptionMuteExpires_Hours_zero, "\(value)") + return String(format: self._ServiceMessage_GameScoreSelfExtended_zero, "\(value)") case .one: - return String(format: self._Notifications_ExceptionMuteExpires_Hours_one, "\(value)") + return String(format: self._ServiceMessage_GameScoreSelfExtended_one, "\(value)") case .two: - return String(format: self._Notifications_ExceptionMuteExpires_Hours_two, "\(value)") + return String(format: self._ServiceMessage_GameScoreSelfExtended_two, "\(value)") case .few: - return String(format: self._Notifications_ExceptionMuteExpires_Hours_few, "\(value)") + return String(format: self._ServiceMessage_GameScoreSelfExtended_few, "\(value)") case .many: - return String(format: self._Notifications_ExceptionMuteExpires_Hours_many, "\(value)") + return String(format: self._ServiceMessage_GameScoreSelfExtended_many, "\(value)") case .other: - return String(format: self._Notifications_ExceptionMuteExpires_Hours_other, "\(value)") + return String(format: self._ServiceMessage_GameScoreSelfExtended_other, "\(value)") + } + } + private let _LiveLocation_MenuChatsCount_zero: String + private let _LiveLocation_MenuChatsCount_one: String + private let _LiveLocation_MenuChatsCount_two: String + private let _LiveLocation_MenuChatsCount_few: String + private let _LiveLocation_MenuChatsCount_many: String + private let _LiveLocation_MenuChatsCount_other: String + public func LiveLocation_MenuChatsCount(_ value: Int32) -> String { + switch presentationStringsPluralizationForm(self.lc, value) { + case .zero: + return String(format: self._LiveLocation_MenuChatsCount_zero, "\(value)") + case .one: + return String(format: self._LiveLocation_MenuChatsCount_one, "\(value)") + case .two: + return String(format: self._LiveLocation_MenuChatsCount_two, "\(value)") + case .few: + return String(format: self._LiveLocation_MenuChatsCount_few, "\(value)") + case .many: + return String(format: self._LiveLocation_MenuChatsCount_many, "\(value)") + case .other: + return String(format: self._LiveLocation_MenuChatsCount_other, "\(value)") + } + } + private let _Call_Seconds_zero: String + private let _Call_Seconds_one: String + private let _Call_Seconds_two: String + private let _Call_Seconds_few: String + private let _Call_Seconds_many: String + private let _Call_Seconds_other: String + public func Call_Seconds(_ value: Int32) -> String { + switch presentationStringsPluralizationForm(self.lc, value) { + case .zero: + return String(format: self._Call_Seconds_zero, "\(value)") + case .one: + return String(format: self._Call_Seconds_one, "\(value)") + case .two: + return String(format: self._Call_Seconds_two, "\(value)") + case .few: + return String(format: self._Call_Seconds_few, "\(value)") + case .many: + return String(format: self._Call_Seconds_many, "\(value)") + case .other: + return String(format: self._Call_Seconds_other, "\(value)") + } + } + private let _Call_Minutes_zero: String + private let _Call_Minutes_one: String + private let _Call_Minutes_two: String + private let _Call_Minutes_few: String + private let _Call_Minutes_many: String + private let _Call_Minutes_other: String + public func Call_Minutes(_ value: Int32) -> String { + switch presentationStringsPluralizationForm(self.lc, value) { + case .zero: + return String(format: self._Call_Minutes_zero, "\(value)") + case .one: + return String(format: self._Call_Minutes_one, "\(value)") + case .two: + return String(format: self._Call_Minutes_two, "\(value)") + case .few: + return String(format: self._Call_Minutes_few, "\(value)") + case .many: + return String(format: self._Call_Minutes_many, "\(value)") + case .other: + return String(format: self._Call_Minutes_other, "\(value)") + } + } + private let _Conversation_StatusMembers_zero: String + private let _Conversation_StatusMembers_one: String + private let _Conversation_StatusMembers_two: String + private let _Conversation_StatusMembers_few: String + private let _Conversation_StatusMembers_many: String + private let _Conversation_StatusMembers_other: String + public func Conversation_StatusMembers(_ value: Int32) -> String { + switch presentationStringsPluralizationForm(self.lc, value) { + case .zero: + return String(format: self._Conversation_StatusMembers_zero, "\(value)") + case .one: + return String(format: self._Conversation_StatusMembers_one, "\(value)") + case .two: + return String(format: self._Conversation_StatusMembers_two, "\(value)") + case .few: + return String(format: self._Conversation_StatusMembers_few, "\(value)") + case .many: + return String(format: self._Conversation_StatusMembers_many, "\(value)") + case .other: + return String(format: self._Conversation_StatusMembers_other, "\(value)") + } + } + private let _InviteText_ContactsCount_zero: String + private let _InviteText_ContactsCount_one: String + private let _InviteText_ContactsCount_two: String + private let _InviteText_ContactsCount_few: String + private let _InviteText_ContactsCount_many: String + private let _InviteText_ContactsCount_other: String + public func InviteText_ContactsCount(_ value: Int32) -> String { + switch presentationStringsPluralizationForm(self.lc, value) { + case .zero: + return String(format: self._InviteText_ContactsCount_zero, "\(value)") + case .one: + return String(format: self._InviteText_ContactsCount_one, "\(value)") + case .two: + return String(format: self._InviteText_ContactsCount_two, "\(value)") + case .few: + return String(format: self._InviteText_ContactsCount_few, "\(value)") + case .many: + return String(format: self._InviteText_ContactsCount_many, "\(value)") + case .other: + return String(format: self._InviteText_ContactsCount_other, "\(value)") + } + } + private let _Contacts_ImportersCount_zero: String + private let _Contacts_ImportersCount_one: String + private let _Contacts_ImportersCount_two: String + private let _Contacts_ImportersCount_few: String + private let _Contacts_ImportersCount_many: String + private let _Contacts_ImportersCount_other: String + public func Contacts_ImportersCount(_ value: Int32) -> String { + switch presentationStringsPluralizationForm(self.lc, value) { + case .zero: + return String(format: self._Contacts_ImportersCount_zero, "\(value)") + case .one: + return String(format: self._Contacts_ImportersCount_one, "\(value)") + case .two: + return String(format: self._Contacts_ImportersCount_two, "\(value)") + case .few: + return String(format: self._Contacts_ImportersCount_few, "\(value)") + case .many: + return String(format: self._Contacts_ImportersCount_many, "\(value)") + case .other: + return String(format: self._Contacts_ImportersCount_other, "\(value)") } } private let _Invitation_Members_zero: String @@ -5451,6 +5018,468 @@ public final class PresentationStrings { return String(format: self._Invitation_Members_other, "\(value)") } } + private let _Conversation_StatusOnline_zero: String + private let _Conversation_StatusOnline_one: String + private let _Conversation_StatusOnline_two: String + private let _Conversation_StatusOnline_few: String + private let _Conversation_StatusOnline_many: String + private let _Conversation_StatusOnline_other: String + public func Conversation_StatusOnline(_ value: Int32) -> String { + switch presentationStringsPluralizationForm(self.lc, value) { + case .zero: + return String(format: self._Conversation_StatusOnline_zero, "\(value)") + case .one: + return String(format: self._Conversation_StatusOnline_one, "\(value)") + case .two: + return String(format: self._Conversation_StatusOnline_two, "\(value)") + case .few: + return String(format: self._Conversation_StatusOnline_few, "\(value)") + case .many: + return String(format: self._Conversation_StatusOnline_many, "\(value)") + case .other: + return String(format: self._Conversation_StatusOnline_other, "\(value)") + } + } + private let _MessageTimer_Years_zero: String + private let _MessageTimer_Years_one: String + private let _MessageTimer_Years_two: String + private let _MessageTimer_Years_few: String + private let _MessageTimer_Years_many: String + private let _MessageTimer_Years_other: String + public func MessageTimer_Years(_ value: Int32) -> String { + switch presentationStringsPluralizationForm(self.lc, value) { + case .zero: + return String(format: self._MessageTimer_Years_zero, "\(value)") + case .one: + return String(format: self._MessageTimer_Years_one, "\(value)") + case .two: + return String(format: self._MessageTimer_Years_two, "\(value)") + case .few: + return String(format: self._MessageTimer_Years_few, "\(value)") + case .many: + return String(format: self._MessageTimer_Years_many, "\(value)") + case .other: + return String(format: self._MessageTimer_Years_other, "\(value)") + } + } + private let _ForwardedStickers_zero: String + private let _ForwardedStickers_one: String + private let _ForwardedStickers_two: String + private let _ForwardedStickers_few: String + private let _ForwardedStickers_many: String + private let _ForwardedStickers_other: String + public func ForwardedStickers(_ value: Int32) -> String { + switch presentationStringsPluralizationForm(self.lc, value) { + case .zero: + return String(format: self._ForwardedStickers_zero, "\(value)") + case .one: + return String(format: self._ForwardedStickers_one, "\(value)") + case .two: + return String(format: self._ForwardedStickers_two, "\(value)") + case .few: + return String(format: self._ForwardedStickers_few, "\(value)") + case .many: + return String(format: self._ForwardedStickers_many, "\(value)") + case .other: + return String(format: self._ForwardedStickers_other, "\(value)") + } + } + private let _StickerPack_StickerCount_zero: String + private let _StickerPack_StickerCount_one: String + private let _StickerPack_StickerCount_two: String + private let _StickerPack_StickerCount_few: String + private let _StickerPack_StickerCount_many: String + private let _StickerPack_StickerCount_other: String + public func StickerPack_StickerCount(_ value: Int32) -> String { + switch presentationStringsPluralizationForm(self.lc, value) { + case .zero: + return String(format: self._StickerPack_StickerCount_zero, "\(value)") + case .one: + return String(format: self._StickerPack_StickerCount_one, "\(value)") + case .two: + return String(format: self._StickerPack_StickerCount_two, "\(value)") + case .few: + return String(format: self._StickerPack_StickerCount_few, "\(value)") + case .many: + return String(format: self._StickerPack_StickerCount_many, "\(value)") + case .other: + return String(format: self._StickerPack_StickerCount_other, "\(value)") + } + } + private let _Watch_LastSeen_MinutesAgo_zero: String + private let _Watch_LastSeen_MinutesAgo_one: String + private let _Watch_LastSeen_MinutesAgo_two: String + private let _Watch_LastSeen_MinutesAgo_few: String + private let _Watch_LastSeen_MinutesAgo_many: String + private let _Watch_LastSeen_MinutesAgo_other: String + public func Watch_LastSeen_MinutesAgo(_ value: Int32) -> String { + switch presentationStringsPluralizationForm(self.lc, value) { + case .zero: + return String(format: self._Watch_LastSeen_MinutesAgo_zero, "\(value)") + case .one: + return String(format: self._Watch_LastSeen_MinutesAgo_one, "\(value)") + case .two: + return String(format: self._Watch_LastSeen_MinutesAgo_two, "\(value)") + case .few: + return String(format: self._Watch_LastSeen_MinutesAgo_few, "\(value)") + case .many: + return String(format: self._Watch_LastSeen_MinutesAgo_many, "\(value)") + case .other: + return String(format: self._Watch_LastSeen_MinutesAgo_other, "\(value)") + } + } + private let _Notification_GameScoreSelfSimple_zero: String + private let _Notification_GameScoreSelfSimple_one: String + private let _Notification_GameScoreSelfSimple_two: String + private let _Notification_GameScoreSelfSimple_few: String + private let _Notification_GameScoreSelfSimple_many: String + private let _Notification_GameScoreSelfSimple_other: String + public func Notification_GameScoreSelfSimple(_ value: Int32) -> String { + switch presentationStringsPluralizationForm(self.lc, value) { + case .zero: + return String(format: self._Notification_GameScoreSelfSimple_zero, "\(value)") + case .one: + return String(format: self._Notification_GameScoreSelfSimple_one, "\(value)") + case .two: + return String(format: self._Notification_GameScoreSelfSimple_two, "\(value)") + case .few: + return String(format: self._Notification_GameScoreSelfSimple_few, "\(value)") + case .many: + return String(format: self._Notification_GameScoreSelfSimple_many, "\(value)") + case .other: + return String(format: self._Notification_GameScoreSelfSimple_other, "\(value)") + } + } + private let _ServiceMessage_GameScoreSimple_zero: String + private let _ServiceMessage_GameScoreSimple_one: String + private let _ServiceMessage_GameScoreSimple_two: String + private let _ServiceMessage_GameScoreSimple_few: String + private let _ServiceMessage_GameScoreSimple_many: String + private let _ServiceMessage_GameScoreSimple_other: String + public func ServiceMessage_GameScoreSimple(_ value: Int32) -> String { + switch presentationStringsPluralizationForm(self.lc, value) { + case .zero: + return String(format: self._ServiceMessage_GameScoreSimple_zero, "\(value)") + case .one: + return String(format: self._ServiceMessage_GameScoreSimple_one, "\(value)") + case .two: + return String(format: self._ServiceMessage_GameScoreSimple_two, "\(value)") + case .few: + return String(format: self._ServiceMessage_GameScoreSimple_few, "\(value)") + case .many: + return String(format: self._ServiceMessage_GameScoreSimple_many, "\(value)") + case .other: + return String(format: self._ServiceMessage_GameScoreSimple_other, "\(value)") + } + } + private let _LastSeen_HoursAgo_zero: String + private let _LastSeen_HoursAgo_one: String + private let _LastSeen_HoursAgo_two: String + private let _LastSeen_HoursAgo_few: String + private let _LastSeen_HoursAgo_many: String + private let _LastSeen_HoursAgo_other: String + public func LastSeen_HoursAgo(_ value: Int32) -> String { + switch presentationStringsPluralizationForm(self.lc, value) { + case .zero: + return String(format: self._LastSeen_HoursAgo_zero, "\(value)") + case .one: + return String(format: self._LastSeen_HoursAgo_one, "\(value)") + case .two: + return String(format: self._LastSeen_HoursAgo_two, "\(value)") + case .few: + return String(format: self._LastSeen_HoursAgo_few, "\(value)") + case .many: + return String(format: self._LastSeen_HoursAgo_many, "\(value)") + case .other: + return String(format: self._LastSeen_HoursAgo_other, "\(value)") + } + } + private let _Map_ETAMinutes_zero: String + private let _Map_ETAMinutes_one: String + private let _Map_ETAMinutes_two: String + private let _Map_ETAMinutes_few: String + private let _Map_ETAMinutes_many: String + private let _Map_ETAMinutes_other: String + public func Map_ETAMinutes(_ value: Int32) -> String { + switch presentationStringsPluralizationForm(self.lc, value) { + case .zero: + return String(format: self._Map_ETAMinutes_zero, "\(value)") + case .one: + return String(format: self._Map_ETAMinutes_one, "\(value)") + case .two: + return String(format: self._Map_ETAMinutes_two, "\(value)") + case .few: + return String(format: self._Map_ETAMinutes_few, "\(value)") + case .many: + return String(format: self._Map_ETAMinutes_many, "\(value)") + case .other: + return String(format: self._Map_ETAMinutes_other, "\(value)") + } + } + private let _Notifications_ExceptionMuteExpires_Minutes_zero: String + private let _Notifications_ExceptionMuteExpires_Minutes_one: String + private let _Notifications_ExceptionMuteExpires_Minutes_two: String + private let _Notifications_ExceptionMuteExpires_Minutes_few: String + private let _Notifications_ExceptionMuteExpires_Minutes_many: String + private let _Notifications_ExceptionMuteExpires_Minutes_other: String + public func Notifications_ExceptionMuteExpires_Minutes(_ value: Int32) -> String { + switch presentationStringsPluralizationForm(self.lc, value) { + case .zero: + return String(format: self._Notifications_ExceptionMuteExpires_Minutes_zero, "\(value)") + case .one: + return String(format: self._Notifications_ExceptionMuteExpires_Minutes_one, "\(value)") + case .two: + return String(format: self._Notifications_ExceptionMuteExpires_Minutes_two, "\(value)") + case .few: + return String(format: self._Notifications_ExceptionMuteExpires_Minutes_few, "\(value)") + case .many: + return String(format: self._Notifications_ExceptionMuteExpires_Minutes_many, "\(value)") + case .other: + return String(format: self._Notifications_ExceptionMuteExpires_Minutes_other, "\(value)") + } + } + private let _GroupInfo_ParticipantCount_zero: String + private let _GroupInfo_ParticipantCount_one: String + private let _GroupInfo_ParticipantCount_two: String + private let _GroupInfo_ParticipantCount_few: String + private let _GroupInfo_ParticipantCount_many: String + private let _GroupInfo_ParticipantCount_other: String + public func GroupInfo_ParticipantCount(_ value: Int32) -> String { + switch presentationStringsPluralizationForm(self.lc, value) { + case .zero: + return String(format: self._GroupInfo_ParticipantCount_zero, "\(value)") + case .one: + return String(format: self._GroupInfo_ParticipantCount_one, "\(value)") + case .two: + return String(format: self._GroupInfo_ParticipantCount_two, "\(value)") + case .few: + return String(format: self._GroupInfo_ParticipantCount_few, "\(value)") + case .many: + return String(format: self._GroupInfo_ParticipantCount_many, "\(value)") + case .other: + return String(format: self._GroupInfo_ParticipantCount_other, "\(value)") + } + } + private let _ForwardedVideos_zero: String + private let _ForwardedVideos_one: String + private let _ForwardedVideos_two: String + private let _ForwardedVideos_few: String + private let _ForwardedVideos_many: String + private let _ForwardedVideos_other: String + public func ForwardedVideos(_ value: Int32) -> String { + switch presentationStringsPluralizationForm(self.lc, value) { + case .zero: + return String(format: self._ForwardedVideos_zero, "\(value)") + case .one: + return String(format: self._ForwardedVideos_one, "\(value)") + case .two: + return String(format: self._ForwardedVideos_two, "\(value)") + case .few: + return String(format: self._ForwardedVideos_few, "\(value)") + case .many: + return String(format: self._ForwardedVideos_many, "\(value)") + case .other: + return String(format: self._ForwardedVideos_other, "\(value)") + } + } + private let _MessageTimer_ShortMinutes_zero: String + private let _MessageTimer_ShortMinutes_one: String + private let _MessageTimer_ShortMinutes_two: String + private let _MessageTimer_ShortMinutes_few: String + private let _MessageTimer_ShortMinutes_many: String + private let _MessageTimer_ShortMinutes_other: String + public func MessageTimer_ShortMinutes(_ value: Int32) -> String { + switch presentationStringsPluralizationForm(self.lc, value) { + case .zero: + return String(format: self._MessageTimer_ShortMinutes_zero, "\(value)") + case .one: + return String(format: self._MessageTimer_ShortMinutes_one, "\(value)") + case .two: + return String(format: self._MessageTimer_ShortMinutes_two, "\(value)") + case .few: + return String(format: self._MessageTimer_ShortMinutes_few, "\(value)") + case .many: + return String(format: self._MessageTimer_ShortMinutes_many, "\(value)") + case .other: + return String(format: self._MessageTimer_ShortMinutes_other, "\(value)") + } + } + private let _ForwardedAuthorsOthers_zero: String + private let _ForwardedAuthorsOthers_one: String + private let _ForwardedAuthorsOthers_two: String + private let _ForwardedAuthorsOthers_few: String + private let _ForwardedAuthorsOthers_many: String + private let _ForwardedAuthorsOthers_other: String + public func ForwardedAuthorsOthers(_ value: Int32) -> String { + switch presentationStringsPluralizationForm(self.lc, value) { + case .zero: + return String(format: self._ForwardedAuthorsOthers_zero, "\(value)") + case .one: + return String(format: self._ForwardedAuthorsOthers_one, "\(value)") + case .two: + return String(format: self._ForwardedAuthorsOthers_two, "\(value)") + case .few: + return String(format: self._ForwardedAuthorsOthers_few, "\(value)") + case .many: + return String(format: self._ForwardedAuthorsOthers_many, "\(value)") + case .other: + return String(format: self._ForwardedAuthorsOthers_other, "\(value)") + } + } + private let _Call_ShortSeconds_zero: String + private let _Call_ShortSeconds_one: String + private let _Call_ShortSeconds_two: String + private let _Call_ShortSeconds_few: String + private let _Call_ShortSeconds_many: String + private let _Call_ShortSeconds_other: String + public func Call_ShortSeconds(_ value: Int32) -> String { + switch presentationStringsPluralizationForm(self.lc, value) { + case .zero: + return String(format: self._Call_ShortSeconds_zero, "\(value)") + case .one: + return String(format: self._Call_ShortSeconds_one, "\(value)") + case .two: + return String(format: self._Call_ShortSeconds_two, "\(value)") + case .few: + return String(format: self._Call_ShortSeconds_few, "\(value)") + case .many: + return String(format: self._Call_ShortSeconds_many, "\(value)") + case .other: + return String(format: self._Call_ShortSeconds_other, "\(value)") + } + } + private let _SharedMedia_Generic_zero: String + private let _SharedMedia_Generic_one: String + private let _SharedMedia_Generic_two: String + private let _SharedMedia_Generic_few: String + private let _SharedMedia_Generic_many: String + private let _SharedMedia_Generic_other: String + public func SharedMedia_Generic(_ value: Int32) -> String { + switch presentationStringsPluralizationForm(self.lc, value) { + case .zero: + return String(format: self._SharedMedia_Generic_zero, "\(value)") + case .one: + return String(format: self._SharedMedia_Generic_one, "\(value)") + case .two: + return String(format: self._SharedMedia_Generic_two, "\(value)") + case .few: + return String(format: self._SharedMedia_Generic_few, "\(value)") + case .many: + return String(format: self._SharedMedia_Generic_many, "\(value)") + case .other: + return String(format: self._SharedMedia_Generic_other, "\(value)") + } + } + private let _ForwardedAudios_zero: String + private let _ForwardedAudios_one: String + private let _ForwardedAudios_two: String + private let _ForwardedAudios_few: String + private let _ForwardedAudios_many: String + private let _ForwardedAudios_other: String + public func ForwardedAudios(_ value: Int32) -> String { + switch presentationStringsPluralizationForm(self.lc, value) { + case .zero: + return String(format: self._ForwardedAudios_zero, "\(value)") + case .one: + return String(format: self._ForwardedAudios_one, "\(value)") + case .two: + return String(format: self._ForwardedAudios_two, "\(value)") + case .few: + return String(format: self._ForwardedAudios_few, "\(value)") + case .many: + return String(format: self._ForwardedAudios_many, "\(value)") + case .other: + return String(format: self._ForwardedAudios_other, "\(value)") + } + } + private let _DialogList_LiveLocationChatsCount_zero: String + private let _DialogList_LiveLocationChatsCount_one: String + private let _DialogList_LiveLocationChatsCount_two: String + private let _DialogList_LiveLocationChatsCount_few: String + private let _DialogList_LiveLocationChatsCount_many: String + private let _DialogList_LiveLocationChatsCount_other: String + public func DialogList_LiveLocationChatsCount(_ value: Int32) -> String { + switch presentationStringsPluralizationForm(self.lc, value) { + case .zero: + return String(format: self._DialogList_LiveLocationChatsCount_zero, "\(value)") + case .one: + return String(format: self._DialogList_LiveLocationChatsCount_one, "\(value)") + case .two: + return String(format: self._DialogList_LiveLocationChatsCount_two, "\(value)") + case .few: + return String(format: self._DialogList_LiveLocationChatsCount_few, "\(value)") + case .many: + return String(format: self._DialogList_LiveLocationChatsCount_many, "\(value)") + case .other: + return String(format: self._DialogList_LiveLocationChatsCount_other, "\(value)") + } + } + private let _Watch_UserInfo_Mute_zero: String + private let _Watch_UserInfo_Mute_one: String + private let _Watch_UserInfo_Mute_two: String + private let _Watch_UserInfo_Mute_few: String + private let _Watch_UserInfo_Mute_many: String + private let _Watch_UserInfo_Mute_other: String + public func Watch_UserInfo_Mute(_ value: Int32) -> String { + switch presentationStringsPluralizationForm(self.lc, value) { + case .zero: + return String(format: self._Watch_UserInfo_Mute_zero, "\(value)") + case .one: + return String(format: self._Watch_UserInfo_Mute_one, "\(value)") + case .two: + return String(format: self._Watch_UserInfo_Mute_two, "\(value)") + case .few: + return String(format: self._Watch_UserInfo_Mute_few, "\(value)") + case .many: + return String(format: self._Watch_UserInfo_Mute_many, "\(value)") + case .other: + return String(format: self._Watch_UserInfo_Mute_other, "\(value)") + } + } + private let _Conversation_LiveLocationMembersCount_zero: String + private let _Conversation_LiveLocationMembersCount_one: String + private let _Conversation_LiveLocationMembersCount_two: String + private let _Conversation_LiveLocationMembersCount_few: String + private let _Conversation_LiveLocationMembersCount_many: String + private let _Conversation_LiveLocationMembersCount_other: String + public func Conversation_LiveLocationMembersCount(_ value: Int32) -> String { + switch presentationStringsPluralizationForm(self.lc, value) { + case .zero: + return String(format: self._Conversation_LiveLocationMembersCount_zero, "\(value)") + case .one: + return String(format: self._Conversation_LiveLocationMembersCount_one, "\(value)") + case .two: + return String(format: self._Conversation_LiveLocationMembersCount_two, "\(value)") + case .few: + return String(format: self._Conversation_LiveLocationMembersCount_few, "\(value)") + case .many: + return String(format: self._Conversation_LiveLocationMembersCount_many, "\(value)") + case .other: + return String(format: self._Conversation_LiveLocationMembersCount_other, "\(value)") + } + } + private let _ForwardedFiles_zero: String + private let _ForwardedFiles_one: String + private let _ForwardedFiles_two: String + private let _ForwardedFiles_few: String + private let _ForwardedFiles_many: String + private let _ForwardedFiles_other: String + public func ForwardedFiles(_ value: Int32) -> String { + switch presentationStringsPluralizationForm(self.lc, value) { + case .zero: + return String(format: self._ForwardedFiles_zero, "\(value)") + case .one: + return String(format: self._ForwardedFiles_one, "\(value)") + case .two: + return String(format: self._ForwardedFiles_two, "\(value)") + case .few: + return String(format: self._ForwardedFiles_few, "\(value)") + case .many: + return String(format: self._ForwardedFiles_many, "\(value)") + case .other: + return String(format: self._ForwardedFiles_other, "\(value)") + } + } init(languageCode: String, dict: [String: String]) { @@ -5501,6 +5530,7 @@ public final class PresentationStrings { self.Passport_Language_el = getValue(dict, "Passport.Language.el") self.Passport_Identity_DateOfBirth = getValue(dict, "Passport.Identity.DateOfBirth") self.TwoStepAuth_SetupPasswordConfirmPassword = getValue(dict, "TwoStepAuth.SetupPasswordConfirmPassword") + self.SocksProxySetup_PasteFromClipboard = getValue(dict, "SocksProxySetup.PasteFromClipboard") self.ChannelIntro_Text = getValue(dict, "ChannelIntro.Text") self.PrivacySettings_SecurityTitle = getValue(dict, "PrivacySettings.SecurityTitle") self.DialogList_SavedMessages = getValue(dict, "DialogList.SavedMessages") @@ -5540,10 +5570,10 @@ public final class PresentationStrings { self._Channel_AdminLog_MessageEdited = getValue(dict, "Channel.AdminLog.MessageEdited") self._Channel_AdminLog_MessageEdited_r = extractArgumentRanges(self._Channel_AdminLog_MessageEdited) self.Group_Setup_HistoryHidden = getValue(dict, "Group.Setup.HistoryHidden") - self.Your_cards_expiration_year_is_invalid = getValue(dict, "Your_cards_expiration_year_is_invalid") - self.AccessDenied_MicrophoneRestricted = getValue(dict, "AccessDenied.MicrophoneRestricted") self._PHONE_CALL_REQUEST = getValue(dict, "PHONE_CALL_REQUEST") self._PHONE_CALL_REQUEST_r = extractArgumentRanges(self._PHONE_CALL_REQUEST) + self.AccessDenied_MicrophoneRestricted = getValue(dict, "AccessDenied.MicrophoneRestricted") + self.Your_cards_expiration_year_is_invalid = getValue(dict, "Your_cards_expiration_year_is_invalid") self.GroupInfo_InviteByLink = getValue(dict, "GroupInfo.InviteByLink") self._Notification_LeftChat = getValue(dict, "Notification.LeftChat") self._Notification_LeftChat_r = extractArgumentRanges(self._Notification_LeftChat) @@ -5559,8 +5589,6 @@ public final class PresentationStrings { self.SocksProxySetup_Hostname = getValue(dict, "SocksProxySetup.Hostname") self._PrivacyPolicy_AgeVerificationMessage = getValue(dict, "PrivacyPolicy.AgeVerificationMessage") self._PrivacyPolicy_AgeVerificationMessage_r = extractArgumentRanges(self._PrivacyPolicy_AgeVerificationMessage) - self._Login_TermsOfService_ProceedBot = getValue(dict, "Login.TermsOfService.ProceedBot") - self._Login_TermsOfService_ProceedBot_r = extractArgumentRanges(self._Login_TermsOfService_ProceedBot) self.NotificationsSound_None = getValue(dict, "NotificationsSound.None") self.Channel_AdminLog_CanEditMessages = getValue(dict, "Channel.AdminLog.CanEditMessages") self._MESSAGE_CONTACT = getValue(dict, "MESSAGE_CONTACT") @@ -6419,10 +6447,6 @@ public final class PresentationStrings { self._Time_PreciseDate_m5_r = extractArgumentRanges(self._Time_PreciseDate_m5) self._Channel_AdminLog_MessageKickedNameUsername = getValue(dict, "Channel.AdminLog.MessageKickedNameUsername") self._Channel_AdminLog_MessageKickedNameUsername_r = extractArgumentRanges(self._Channel_AdminLog_MessageKickedNameUsername) - self._Channel_AdminLog_MessageUnkickedName = getValue(dict, "Channel.AdminLog.MessageUnkickedName") - self._Channel_AdminLog_MessageUnkickedName_r = extractArgumentRanges(self._Channel_AdminLog_MessageUnkickedName) - self._Channel_AdminLog_MessageUnkickedNameUsername = getValue(dict, "Channel.AdminLog.MessageUnkickedNameUsername") - self._Channel_AdminLog_MessageUnkickedNameUsername_r = extractArgumentRanges(self._Channel_AdminLog_MessageUnkickedNameUsername) self.Coub_TapForSound = getValue(dict, "Coub.TapForSound") self.Compose_NewEncryptedChat = getValue(dict, "Compose.NewEncryptedChat") self.PhotoEditor_CropReset = getValue(dict, "PhotoEditor.CropReset") @@ -6619,6 +6643,8 @@ public final class PresentationStrings { self.Conversation_GifTooltip = getValue(dict, "Conversation.GifTooltip") self.Passport_Address_EditBankStatement = getValue(dict, "Passport.Address.EditBankStatement") self.CheckoutInfo_ErrorCityInvalid = getValue(dict, "CheckoutInfo.ErrorCityInvalid") + self._CHANNEL_MESSAGE_PHOTOS = getValue(dict, "CHANNEL_MESSAGE_PHOTOS") + self._CHANNEL_MESSAGE_PHOTOS_r = extractArgumentRanges(self._CHANNEL_MESSAGE_PHOTOS) self.Profile_CreateEncryptedChatError = getValue(dict, "Profile.CreateEncryptedChatError") self.Map_LocationTitle = getValue(dict, "Map.LocationTitle") self.Call_RateCall = getValue(dict, "Call.RateCall") @@ -6651,6 +6677,8 @@ public final class PresentationStrings { self.Group_ErrorSendRestrictedStickers = getValue(dict, "Group.ErrorSendRestrictedStickers") self.Bot_GroupStatusDoesNotReadHistory = getValue(dict, "Bot.GroupStatusDoesNotReadHistory") self.Notification_Mute1h = getValue(dict, "Notification.Mute1h") + self._Channel_AdminLog_MessageUnkickedName = getValue(dict, "Channel.AdminLog.MessageUnkickedName") + self._Channel_AdminLog_MessageUnkickedName_r = extractArgumentRanges(self._Channel_AdminLog_MessageUnkickedName) self.Settings_TabTitle = getValue(dict, "Settings.TabTitle") self.Passport_Identity_ExpiryDatePlaceholder = getValue(dict, "Passport.Identity.ExpiryDatePlaceholder") self.NetworkUsageSettings_MediaAudioDataSection = getValue(dict, "NetworkUsageSettings.MediaAudioDataSection") @@ -6667,6 +6695,8 @@ public final class PresentationStrings { self._Conversation_RestrictedStickersTimed = getValue(dict, "Conversation.RestrictedStickersTimed") self._Conversation_RestrictedStickersTimed_r = extractArgumentRanges(self._Conversation_RestrictedStickersTimed) self.Login_InvalidFirstNameError = getValue(dict, "Login.InvalidFirstNameError") + self._Channel_AdminLog_MessageUnkickedNameUsername = getValue(dict, "Channel.AdminLog.MessageUnkickedNameUsername") + self._Channel_AdminLog_MessageUnkickedNameUsername_r = extractArgumentRanges(self._Channel_AdminLog_MessageUnkickedNameUsername) self._Notification_Joined = getValue(dict, "Notification.Joined") self._Notification_Joined_r = extractArgumentRanges(self._Notification_Joined) self.Paint_Clear = getValue(dict, "Paint.Clear") @@ -6749,6 +6779,8 @@ public final class PresentationStrings { self.MediaPicker_TimerTooltip = getValue(dict, "MediaPicker.TimerTooltip") self.Activity_UploadingVideo = getValue(dict, "Activity.UploadingVideo") self.Channel_Info_Management = getValue(dict, "Channel.Info.Management") + self._Login_TermsOfService_ProceedBot = getValue(dict, "Login.TermsOfService.ProceedBot") + self._Login_TermsOfService_ProceedBot_r = extractArgumentRanges(self._Login_TermsOfService_ProceedBot) self._Notification_MessageLifetimeChangedOutgoing = getValue(dict, "Notification.MessageLifetimeChangedOutgoing") self._Notification_MessageLifetimeChangedOutgoing_r = extractArgumentRanges(self._Notification_MessageLifetimeChangedOutgoing) self.PhotoEditor_QualityVeryLow = getValue(dict, "PhotoEditor.QualityVeryLow") @@ -6765,6 +6797,8 @@ public final class PresentationStrings { self.Contacts_AccessDeniedHelpON = getValue(dict, "Contacts.AccessDeniedHelpON") self.Passport_Identity_AddInternalPassport = getValue(dict, "Passport.Identity.AddInternalPassport") self.NetworkUsageSettings_ResetStats = getValue(dict, "NetworkUsageSettings.ResetStats") + self._CHAT_MESSAGE_PHOTOS = getValue(dict, "CHAT_MESSAGE_PHOTOS") + self._CHAT_MESSAGE_PHOTOS_r = extractArgumentRanges(self._CHAT_MESSAGE_PHOTOS) self._PrivacySettings_LastSeenContactsMinusPlus = getValue(dict, "PrivacySettings.LastSeenContactsMinusPlus") self._PrivacySettings_LastSeenContactsMinusPlus_r = extractArgumentRanges(self._PrivacySettings_LastSeenContactsMinusPlus) self.Channel_AdminLog_EmptyMessageText = getValue(dict, "Channel.AdminLog.EmptyMessageText") @@ -7014,6 +7048,8 @@ public final class PresentationStrings { self.Activity_UploadingVideoMessage = getValue(dict, "Activity.UploadingVideoMessage") self.Conversation_ShareBotContactConfirmation = getValue(dict, "Conversation.ShareBotContactConfirmation") self.Login_CodeSentSms = getValue(dict, "Login.CodeSentSms") + self._CHANNEL_MESSAGES = getValue(dict, "CHANNEL_MESSAGES") + self._CHANNEL_MESSAGES_r = extractArgumentRanges(self._CHANNEL_MESSAGES) self.Conversation_ReportSpamConfirmation = getValue(dict, "Conversation.ReportSpamConfirmation") self.ChannelMembers_ChannelAdminsTitle = getValue(dict, "ChannelMembers.ChannelAdminsTitle") self.SocksProxySetup_Credentials = getValue(dict, "SocksProxySetup.Credentials") @@ -7327,6 +7363,7 @@ public final class PresentationStrings { self._CHAT_ADD_YOU = getValue(dict, "CHAT_ADD_YOU") self._CHAT_ADD_YOU_r = extractArgumentRanges(self._CHAT_ADD_YOU) self.CheckoutInfo_ShippingInfoCity = getValue(dict, "CheckoutInfo.ShippingInfoCity") + self.Group_AdminLog_EmptyText = getValue(dict, "Group.AdminLog.EmptyText") self.AutoDownloadSettings_GroupChats = getValue(dict, "AutoDownloadSettings.GroupChats") self.Conversation_ClousStorageInfo_Description3 = getValue(dict, "Conversation.ClousStorageInfo.Description3") self.Notifications_ExceptionsMuted = getValue(dict, "Notifications.ExceptionsMuted") @@ -7496,8 +7533,7 @@ public final class PresentationStrings { self.Watch_Location_Access = getValue(dict, "Watch.Location.Access") self.PrivacySettings_DeleteAccountIfAwayFor = getValue(dict, "PrivacySettings.DeleteAccountIfAwayFor") self.Channel_AdminLog_EmptyFilterText = getValue(dict, "Channel.AdminLog.EmptyFilterText") - self.Channel_AdminLog_EmptyText = getValue(dict, "Channel.AdminLog.EmptyText") - self.Group_AdminLog_EmptyText = getValue(dict, "Group.AdminLog.EmptyText") + self.Broadcast_AdminLog_EmptyText = getValue(dict, "Broadcast.AdminLog.EmptyText") self.PrivacySettings_DeleteAccountTitle = getValue(dict, "PrivacySettings.DeleteAccountTitle") self.Passport_Language_ms = getValue(dict, "Passport.Language.ms") self.PrivacyLastSeenSettings_CustomShareSettings_Delete = getValue(dict, "PrivacyLastSeenSettings.CustomShareSettings.Delete") @@ -7542,11 +7578,12 @@ public final class PresentationStrings { self.AccessDenied_Title = getValue(dict, "AccessDenied.Title") self.SharedMedia_CategoryLinks = getValue(dict, "SharedMedia.CategoryLinks") self.Localization_LanguageOther = getValue(dict, "Localization.LanguageOther") + self._CHAT_MESSAGES = getValue(dict, "CHAT_MESSAGES") + self._CHAT_MESSAGES_r = extractArgumentRanges(self._CHAT_MESSAGES) self.SaveIncomingPhotosSettings_Title = getValue(dict, "SaveIncomingPhotosSettings.Title") self.Passport_Identity_TypeDriversLicense = getValue(dict, "Passport.Identity.TypeDriversLicense") self.FastTwoStepSetup_HintHelp = getValue(dict, "FastTwoStepSetup.HintHelp") self.Notifications_ExceptionsDefaultSound = getValue(dict, "Notifications.ExceptionsDefaultSound") - self.Passport_Language_es = getValue(dict, "Passport.Language.es") self.TwoStepAuth_EmailSkipAlert = getValue(dict, "TwoStepAuth.EmailSkipAlert") self.ChatSettings_Stickers = getValue(dict, "ChatSettings.Stickers") self.Camera_FlashOff = getValue(dict, "Camera.FlashOff") @@ -7558,6 +7595,7 @@ public final class PresentationStrings { self.Conversation_typing = getValue(dict, "Conversation.typing") self.Common_Back = getValue(dict, "Common.Back") self.PrivacySettings_DataSettingsHelp = getValue(dict, "PrivacySettings.DataSettingsHelp") + self.Passport_Language_es = getValue(dict, "Passport.Language.es") self.Common_Search = getValue(dict, "Common.Search") self._CancelResetAccount_Success = getValue(dict, "CancelResetAccount.Success") self._CancelResetAccount_Success_r = extractArgumentRanges(self._CancelResetAccount_Success) @@ -7696,12 +7734,14 @@ public final class PresentationStrings { self.MediaPicker_CameraRoll = getValue(dict, "MediaPicker.CameraRoll") self.Channel_AdminLog_CanPinMessages = getValue(dict, "Channel.AdminLog.CanPinMessages") self.KeyCommand_NewMessage = getValue(dict, "KeyCommand.NewMessage") - self._Time_PreciseDate_m12 = getValue(dict, "Time.PreciseDate_m12") - self._Time_PreciseDate_m12_r = extractArgumentRanges(self._Time_PreciseDate_m12) + self._ChannelInfo_AddParticipantConfirmation = getValue(dict, "ChannelInfo.AddParticipantConfirmation") + self._ChannelInfo_AddParticipantConfirmation_r = extractArgumentRanges(self._ChannelInfo_AddParticipantConfirmation) self.NetworkUsageSettings_TotalSection = getValue(dict, "NetworkUsageSettings.TotalSection") self._PINNED_AUDIO = getValue(dict, "PINNED_AUDIO") self._PINNED_AUDIO_r = extractArgumentRanges(self._PINNED_AUDIO) self.Privacy_GroupsAndChannels = getValue(dict, "Privacy.GroupsAndChannels") + self._Time_PreciseDate_m12 = getValue(dict, "Time.PreciseDate_m12") + self._Time_PreciseDate_m12_r = extractArgumentRanges(self._Time_PreciseDate_m12) self.Conversation_DiscardVoiceMessageDescription = getValue(dict, "Conversation.DiscardVoiceMessageDescription") self.Passport_Address_ScansHelp = getValue(dict, "Passport.Address.ScansHelp") self._Notification_ChangedGroupPhoto = getValue(dict, "Notification.ChangedGroupPhoto") @@ -7739,10 +7779,12 @@ public final class PresentationStrings { self.Group_ErrorAddTooMuchAdmins = getValue(dict, "Group.ErrorAddTooMuchAdmins") self.SocksProxySetup_Password = getValue(dict, "SocksProxySetup.Password") self.Login_SelectCountry_Title = getValue(dict, "Login.SelectCountry.Title") - self.UserInfo_NotificationsDefault = getValue(dict, "UserInfo.NotificationsDefault") + self._MESSAGE_PHOTOS = getValue(dict, "MESSAGE_PHOTOS") + self._MESSAGE_PHOTOS_r = extractArgumentRanges(self._MESSAGE_PHOTOS) self.Notifications_GroupNotificationsHelp = getValue(dict, "Notifications.GroupNotificationsHelp") self.PhotoEditor_CropAspectRatioSquare = getValue(dict, "PhotoEditor.CropAspectRatioSquare") self.Notification_CallOutgoing = getValue(dict, "Notification.CallOutgoing") + self.UserInfo_NotificationsDefault = getValue(dict, "UserInfo.NotificationsDefault") self.Weekday_ShortMonday = getValue(dict, "Weekday.ShortMonday") self.Checkout_Receipt_Title = getValue(dict, "Checkout.Receipt.Title") self.Channel_Edit_AboutItem = getValue(dict, "Channel.Edit.AboutItem") @@ -7762,8 +7804,6 @@ public final class PresentationStrings { self._PINNED_ROUND_r = extractArgumentRanges(self._PINNED_ROUND) self._ChannelInfo_ChannelForbidden = getValue(dict, "ChannelInfo.ChannelForbidden") self._ChannelInfo_ChannelForbidden_r = extractArgumentRanges(self._ChannelInfo_ChannelForbidden) - self._ChannelInfo_AddParticipantConfirmation = getValue(dict, "ChannelInfo.AddParticipantConfirmation") - self._ChannelInfo_AddParticipantConfirmation_r = extractArgumentRanges(self._ChannelInfo_AddParticipantConfirmation) self.Conversation_ShareMyContactInfo = getValue(dict, "Conversation.ShareMyContactInfo") self.SocksProxySetup_UsernamePlaceholder = getValue(dict, "SocksProxySetup.UsernamePlaceholder") self._CHANNEL_MESSAGE_GEO = getValue(dict, "CHANNEL_MESSAGE_GEO") @@ -7894,6 +7934,8 @@ public final class PresentationStrings { self.Map_OpenInGoogleMaps = getValue(dict, "Map.OpenInGoogleMaps") self.Notification_MessageLifetime5s = getValue(dict, "Notification.MessageLifetime5s") self.Contacts_Title = getValue(dict, "Contacts.Title") + self._MESSAGES = getValue(dict, "MESSAGES") + self._MESSAGES_r = extractArgumentRanges(self._MESSAGES) self.Channel_Management_AddModeratorHelp = getValue(dict, "Channel.Management.AddModeratorHelp") self._CHAT_MESSAGE_FWDS = getValue(dict, "CHAT_MESSAGE_FWDS") self._CHAT_MESSAGE_FWDS_r = extractArgumentRanges(self._CHAT_MESSAGE_FWDS) @@ -7932,8 +7974,8 @@ public final class PresentationStrings { self.ExplicitContent_AlertTitle = getValue(dict, "ExplicitContent.AlertTitle") self.Channel_AdminLogFilter_EventsLeaving = getValue(dict, "Channel.AdminLogFilter.EventsLeaving") self.Map_LiveLocationFor8Hours = getValue(dict, "Map.LiveLocationFor8Hours") - self.Checkout_EnterPassword = getValue(dict, "Checkout.EnterPassword") self.StickerPack_HideStickers = getValue(dict, "StickerPack.HideStickers") + self.Checkout_EnterPassword = getValue(dict, "Checkout.EnterPassword") self.UserInfo_NotificationsEnabled = getValue(dict, "UserInfo.NotificationsEnabled") self.InfoPlist_NSLocationAlwaysUsageDescription = getValue(dict, "InfoPlist.NSLocationAlwaysUsageDescription") self.SocksProxySetup_ProxyDetailsTitle = getValue(dict, "SocksProxySetup.ProxyDetailsTitle") @@ -7952,24 +7994,6 @@ public final class PresentationStrings { self.PrivacySettings_PasscodeAndFaceId = getValue(dict, "PrivacySettings.PasscodeAndFaceId") self.Settings_ChatBackground = getValue(dict, "Settings.ChatBackground") self.Login_TermsOfServiceDecline = getValue(dict, "Login.TermsOfServiceDecline") - self._ForwardedFiles_zero = getValueWithForm(dict, "ForwardedFiles", .zero) - self._ForwardedFiles_one = getValueWithForm(dict, "ForwardedFiles", .one) - self._ForwardedFiles_two = getValueWithForm(dict, "ForwardedFiles", .two) - self._ForwardedFiles_few = getValueWithForm(dict, "ForwardedFiles", .few) - self._ForwardedFiles_many = getValueWithForm(dict, "ForwardedFiles", .many) - self._ForwardedFiles_other = getValueWithForm(dict, "ForwardedFiles", .other) - self._Watch_LastSeen_HoursAgo_zero = getValueWithForm(dict, "Watch.LastSeen.HoursAgo", .zero) - self._Watch_LastSeen_HoursAgo_one = getValueWithForm(dict, "Watch.LastSeen.HoursAgo", .one) - self._Watch_LastSeen_HoursAgo_two = getValueWithForm(dict, "Watch.LastSeen.HoursAgo", .two) - self._Watch_LastSeen_HoursAgo_few = getValueWithForm(dict, "Watch.LastSeen.HoursAgo", .few) - self._Watch_LastSeen_HoursAgo_many = getValueWithForm(dict, "Watch.LastSeen.HoursAgo", .many) - self._Watch_LastSeen_HoursAgo_other = getValueWithForm(dict, "Watch.LastSeen.HoursAgo", .other) - self._MessageTimer_ShortDays_zero = getValueWithForm(dict, "MessageTimer.ShortDays", .zero) - self._MessageTimer_ShortDays_one = getValueWithForm(dict, "MessageTimer.ShortDays", .one) - self._MessageTimer_ShortDays_two = getValueWithForm(dict, "MessageTimer.ShortDays", .two) - self._MessageTimer_ShortDays_few = getValueWithForm(dict, "MessageTimer.ShortDays", .few) - self._MessageTimer_ShortDays_many = getValueWithForm(dict, "MessageTimer.ShortDays", .many) - self._MessageTimer_ShortDays_other = getValueWithForm(dict, "MessageTimer.ShortDays", .other) self._LastSeen_MinutesAgo_zero = getValueWithForm(dict, "LastSeen.MinutesAgo", .zero) self._LastSeen_MinutesAgo_one = getValueWithForm(dict, "LastSeen.MinutesAgo", .one) self._LastSeen_MinutesAgo_two = getValueWithForm(dict, "LastSeen.MinutesAgo", .two) @@ -7982,174 +8006,162 @@ public final class PresentationStrings { self._MuteFor_Days_few = getValueWithForm(dict, "MuteFor.Days", .few) self._MuteFor_Days_many = getValueWithForm(dict, "MuteFor.Days", .many) self._MuteFor_Days_other = getValueWithForm(dict, "MuteFor.Days", .other) - self._MessageTimer_Months_zero = getValueWithForm(dict, "MessageTimer.Months", .zero) - self._MessageTimer_Months_one = getValueWithForm(dict, "MessageTimer.Months", .one) - self._MessageTimer_Months_two = getValueWithForm(dict, "MessageTimer.Months", .two) - self._MessageTimer_Months_few = getValueWithForm(dict, "MessageTimer.Months", .few) - self._MessageTimer_Months_many = getValueWithForm(dict, "MessageTimer.Months", .many) - self._MessageTimer_Months_other = getValueWithForm(dict, "MessageTimer.Months", .other) - self._PasscodeSettings_FailedAttempts_zero = getValueWithForm(dict, "PasscodeSettings.FailedAttempts", .zero) - self._PasscodeSettings_FailedAttempts_one = getValueWithForm(dict, "PasscodeSettings.FailedAttempts", .one) - self._PasscodeSettings_FailedAttempts_two = getValueWithForm(dict, "PasscodeSettings.FailedAttempts", .two) - self._PasscodeSettings_FailedAttempts_few = getValueWithForm(dict, "PasscodeSettings.FailedAttempts", .few) - self._PasscodeSettings_FailedAttempts_many = getValueWithForm(dict, "PasscodeSettings.FailedAttempts", .many) - self._PasscodeSettings_FailedAttempts_other = getValueWithForm(dict, "PasscodeSettings.FailedAttempts", .other) - self._ServiceMessage_GameScoreSimple_zero = getValueWithForm(dict, "ServiceMessage.GameScoreSimple", .zero) - self._ServiceMessage_GameScoreSimple_one = getValueWithForm(dict, "ServiceMessage.GameScoreSimple", .one) - self._ServiceMessage_GameScoreSimple_two = getValueWithForm(dict, "ServiceMessage.GameScoreSimple", .two) - self._ServiceMessage_GameScoreSimple_few = getValueWithForm(dict, "ServiceMessage.GameScoreSimple", .few) - self._ServiceMessage_GameScoreSimple_many = getValueWithForm(dict, "ServiceMessage.GameScoreSimple", .many) - self._ServiceMessage_GameScoreSimple_other = getValueWithForm(dict, "ServiceMessage.GameScoreSimple", .other) - self._MessageTimer_ShortWeeks_zero = getValueWithForm(dict, "MessageTimer.ShortWeeks", .zero) - self._MessageTimer_ShortWeeks_one = getValueWithForm(dict, "MessageTimer.ShortWeeks", .one) - self._MessageTimer_ShortWeeks_two = getValueWithForm(dict, "MessageTimer.ShortWeeks", .two) - self._MessageTimer_ShortWeeks_few = getValueWithForm(dict, "MessageTimer.ShortWeeks", .few) - self._MessageTimer_ShortWeeks_many = getValueWithForm(dict, "MessageTimer.ShortWeeks", .many) - self._MessageTimer_ShortWeeks_other = getValueWithForm(dict, "MessageTimer.ShortWeeks", .other) - self._MuteExpires_Days_zero = getValueWithForm(dict, "MuteExpires.Days", .zero) - self._MuteExpires_Days_one = getValueWithForm(dict, "MuteExpires.Days", .one) - self._MuteExpires_Days_two = getValueWithForm(dict, "MuteExpires.Days", .two) - self._MuteExpires_Days_few = getValueWithForm(dict, "MuteExpires.Days", .few) - self._MuteExpires_Days_many = getValueWithForm(dict, "MuteExpires.Days", .many) - self._MuteExpires_Days_other = getValueWithForm(dict, "MuteExpires.Days", .other) - self._Notification_GameScoreExtended_zero = getValueWithForm(dict, "Notification.GameScoreExtended", .zero) - self._Notification_GameScoreExtended_one = getValueWithForm(dict, "Notification.GameScoreExtended", .one) - self._Notification_GameScoreExtended_two = getValueWithForm(dict, "Notification.GameScoreExtended", .two) - self._Notification_GameScoreExtended_few = getValueWithForm(dict, "Notification.GameScoreExtended", .few) - self._Notification_GameScoreExtended_many = getValueWithForm(dict, "Notification.GameScoreExtended", .many) - self._Notification_GameScoreExtended_other = getValueWithForm(dict, "Notification.GameScoreExtended", .other) - self._Notifications_Exceptions_zero = getValueWithForm(dict, "Notifications.Exceptions", .zero) - self._Notifications_Exceptions_one = getValueWithForm(dict, "Notifications.Exceptions", .one) - self._Notifications_Exceptions_two = getValueWithForm(dict, "Notifications.Exceptions", .two) - self._Notifications_Exceptions_few = getValueWithForm(dict, "Notifications.Exceptions", .few) - self._Notifications_Exceptions_many = getValueWithForm(dict, "Notifications.Exceptions", .many) - self._Notifications_Exceptions_other = getValueWithForm(dict, "Notifications.Exceptions", .other) - self._DialogList_LiveLocationChatsCount_zero = getValueWithForm(dict, "DialogList.LiveLocationChatsCount", .zero) - self._DialogList_LiveLocationChatsCount_one = getValueWithForm(dict, "DialogList.LiveLocationChatsCount", .one) - self._DialogList_LiveLocationChatsCount_two = getValueWithForm(dict, "DialogList.LiveLocationChatsCount", .two) - self._DialogList_LiveLocationChatsCount_few = getValueWithForm(dict, "DialogList.LiveLocationChatsCount", .few) - self._DialogList_LiveLocationChatsCount_many = getValueWithForm(dict, "DialogList.LiveLocationChatsCount", .many) - self._DialogList_LiveLocationChatsCount_other = getValueWithForm(dict, "DialogList.LiveLocationChatsCount", .other) - self._ForwardedAuthorsOthers_zero = getValueWithForm(dict, "ForwardedAuthorsOthers", .zero) - self._ForwardedAuthorsOthers_one = getValueWithForm(dict, "ForwardedAuthorsOthers", .one) - self._ForwardedAuthorsOthers_two = getValueWithForm(dict, "ForwardedAuthorsOthers", .two) - self._ForwardedAuthorsOthers_few = getValueWithForm(dict, "ForwardedAuthorsOthers", .few) - self._ForwardedAuthorsOthers_many = getValueWithForm(dict, "ForwardedAuthorsOthers", .many) - self._ForwardedAuthorsOthers_other = getValueWithForm(dict, "ForwardedAuthorsOthers", .other) + self._StickerPack_AddStickerCount_zero = getValueWithForm(dict, "StickerPack.AddStickerCount", .zero) + self._StickerPack_AddStickerCount_one = getValueWithForm(dict, "StickerPack.AddStickerCount", .one) + self._StickerPack_AddStickerCount_two = getValueWithForm(dict, "StickerPack.AddStickerCount", .two) + self._StickerPack_AddStickerCount_few = getValueWithForm(dict, "StickerPack.AddStickerCount", .few) + self._StickerPack_AddStickerCount_many = getValueWithForm(dict, "StickerPack.AddStickerCount", .many) + self._StickerPack_AddStickerCount_other = getValueWithForm(dict, "StickerPack.AddStickerCount", .other) self._StickerPack_AddMaskCount_zero = getValueWithForm(dict, "StickerPack.AddMaskCount", .zero) self._StickerPack_AddMaskCount_one = getValueWithForm(dict, "StickerPack.AddMaskCount", .one) self._StickerPack_AddMaskCount_two = getValueWithForm(dict, "StickerPack.AddMaskCount", .two) self._StickerPack_AddMaskCount_few = getValueWithForm(dict, "StickerPack.AddMaskCount", .few) self._StickerPack_AddMaskCount_many = getValueWithForm(dict, "StickerPack.AddMaskCount", .many) self._StickerPack_AddMaskCount_other = getValueWithForm(dict, "StickerPack.AddMaskCount", .other) - self._ServiceMessage_GameScoreSelfExtended_zero = getValueWithForm(dict, "ServiceMessage.GameScoreSelfExtended", .zero) - self._ServiceMessage_GameScoreSelfExtended_one = getValueWithForm(dict, "ServiceMessage.GameScoreSelfExtended", .one) - self._ServiceMessage_GameScoreSelfExtended_two = getValueWithForm(dict, "ServiceMessage.GameScoreSelfExtended", .two) - self._ServiceMessage_GameScoreSelfExtended_few = getValueWithForm(dict, "ServiceMessage.GameScoreSelfExtended", .few) - self._ServiceMessage_GameScoreSelfExtended_many = getValueWithForm(dict, "ServiceMessage.GameScoreSelfExtended", .many) - self._ServiceMessage_GameScoreSelfExtended_other = getValueWithForm(dict, "ServiceMessage.GameScoreSelfExtended", .other) - self._Map_ETAHours_zero = getValueWithForm(dict, "Map.ETAHours", .zero) - self._Map_ETAHours_one = getValueWithForm(dict, "Map.ETAHours", .one) - self._Map_ETAHours_two = getValueWithForm(dict, "Map.ETAHours", .two) - self._Map_ETAHours_few = getValueWithForm(dict, "Map.ETAHours", .few) - self._Map_ETAHours_many = getValueWithForm(dict, "Map.ETAHours", .many) - self._Map_ETAHours_other = getValueWithForm(dict, "Map.ETAHours", .other) - self._SharedMedia_File_zero = getValueWithForm(dict, "SharedMedia.File", .zero) - self._SharedMedia_File_one = getValueWithForm(dict, "SharedMedia.File", .one) - self._SharedMedia_File_two = getValueWithForm(dict, "SharedMedia.File", .two) - self._SharedMedia_File_few = getValueWithForm(dict, "SharedMedia.File", .few) - self._SharedMedia_File_many = getValueWithForm(dict, "SharedMedia.File", .many) - self._SharedMedia_File_other = getValueWithForm(dict, "SharedMedia.File", .other) - self._MessageTimer_Days_zero = getValueWithForm(dict, "MessageTimer.Days", .zero) - self._MessageTimer_Days_one = getValueWithForm(dict, "MessageTimer.Days", .one) - self._MessageTimer_Days_two = getValueWithForm(dict, "MessageTimer.Days", .two) - self._MessageTimer_Days_few = getValueWithForm(dict, "MessageTimer.Days", .few) - self._MessageTimer_Days_many = getValueWithForm(dict, "MessageTimer.Days", .many) - self._MessageTimer_Days_other = getValueWithForm(dict, "MessageTimer.Days", .other) - self._ForwardedStickers_zero = getValueWithForm(dict, "ForwardedStickers", .zero) - self._ForwardedStickers_one = getValueWithForm(dict, "ForwardedStickers", .one) - self._ForwardedStickers_two = getValueWithForm(dict, "ForwardedStickers", .two) - self._ForwardedStickers_few = getValueWithForm(dict, "ForwardedStickers", .few) - self._ForwardedStickers_many = getValueWithForm(dict, "ForwardedStickers", .many) - self._ForwardedStickers_other = getValueWithForm(dict, "ForwardedStickers", .other) - self._ServiceMessage_GameScoreExtended_zero = getValueWithForm(dict, "ServiceMessage.GameScoreExtended", .zero) - self._ServiceMessage_GameScoreExtended_one = getValueWithForm(dict, "ServiceMessage.GameScoreExtended", .one) - self._ServiceMessage_GameScoreExtended_two = getValueWithForm(dict, "ServiceMessage.GameScoreExtended", .two) - self._ServiceMessage_GameScoreExtended_few = getValueWithForm(dict, "ServiceMessage.GameScoreExtended", .few) - self._ServiceMessage_GameScoreExtended_many = getValueWithForm(dict, "ServiceMessage.GameScoreExtended", .many) - self._ServiceMessage_GameScoreExtended_other = getValueWithForm(dict, "ServiceMessage.GameScoreExtended", .other) - self._ServiceMessage_GameScoreSelfSimple_zero = getValueWithForm(dict, "ServiceMessage.GameScoreSelfSimple", .zero) - self._ServiceMessage_GameScoreSelfSimple_one = getValueWithForm(dict, "ServiceMessage.GameScoreSelfSimple", .one) - self._ServiceMessage_GameScoreSelfSimple_two = getValueWithForm(dict, "ServiceMessage.GameScoreSelfSimple", .two) - self._ServiceMessage_GameScoreSelfSimple_few = getValueWithForm(dict, "ServiceMessage.GameScoreSelfSimple", .few) - self._ServiceMessage_GameScoreSelfSimple_many = getValueWithForm(dict, "ServiceMessage.GameScoreSelfSimple", .many) - self._ServiceMessage_GameScoreSelfSimple_other = getValueWithForm(dict, "ServiceMessage.GameScoreSelfSimple", .other) - self._LiveLocation_MenuChatsCount_zero = getValueWithForm(dict, "LiveLocation.MenuChatsCount", .zero) - self._LiveLocation_MenuChatsCount_one = getValueWithForm(dict, "LiveLocation.MenuChatsCount", .one) - self._LiveLocation_MenuChatsCount_two = getValueWithForm(dict, "LiveLocation.MenuChatsCount", .two) - self._LiveLocation_MenuChatsCount_few = getValueWithForm(dict, "LiveLocation.MenuChatsCount", .few) - self._LiveLocation_MenuChatsCount_many = getValueWithForm(dict, "LiveLocation.MenuChatsCount", .many) - self._LiveLocation_MenuChatsCount_other = getValueWithForm(dict, "LiveLocation.MenuChatsCount", .other) + self._Notification_GameScoreSimple_zero = getValueWithForm(dict, "Notification.GameScoreSimple", .zero) + self._Notification_GameScoreSimple_one = getValueWithForm(dict, "Notification.GameScoreSimple", .one) + self._Notification_GameScoreSimple_two = getValueWithForm(dict, "Notification.GameScoreSimple", .two) + self._Notification_GameScoreSimple_few = getValueWithForm(dict, "Notification.GameScoreSimple", .few) + self._Notification_GameScoreSimple_many = getValueWithForm(dict, "Notification.GameScoreSimple", .many) + self._Notification_GameScoreSimple_other = getValueWithForm(dict, "Notification.GameScoreSimple", .other) + self._Media_SharePhoto_zero = getValueWithForm(dict, "Media.SharePhoto", .zero) + self._Media_SharePhoto_one = getValueWithForm(dict, "Media.SharePhoto", .one) + self._Media_SharePhoto_two = getValueWithForm(dict, "Media.SharePhoto", .two) + self._Media_SharePhoto_few = getValueWithForm(dict, "Media.SharePhoto", .few) + self._Media_SharePhoto_many = getValueWithForm(dict, "Media.SharePhoto", .many) + self._Media_SharePhoto_other = getValueWithForm(dict, "Media.SharePhoto", .other) + self._SharedMedia_Photo_zero = getValueWithForm(dict, "SharedMedia.Photo", .zero) + self._SharedMedia_Photo_one = getValueWithForm(dict, "SharedMedia.Photo", .one) + self._SharedMedia_Photo_two = getValueWithForm(dict, "SharedMedia.Photo", .two) + self._SharedMedia_Photo_few = getValueWithForm(dict, "SharedMedia.Photo", .few) + self._SharedMedia_Photo_many = getValueWithForm(dict, "SharedMedia.Photo", .many) + self._SharedMedia_Photo_other = getValueWithForm(dict, "SharedMedia.Photo", .other) self._MessageTimer_ShortSeconds_zero = getValueWithForm(dict, "MessageTimer.ShortSeconds", .zero) self._MessageTimer_ShortSeconds_one = getValueWithForm(dict, "MessageTimer.ShortSeconds", .one) self._MessageTimer_ShortSeconds_two = getValueWithForm(dict, "MessageTimer.ShortSeconds", .two) self._MessageTimer_ShortSeconds_few = getValueWithForm(dict, "MessageTimer.ShortSeconds", .few) self._MessageTimer_ShortSeconds_many = getValueWithForm(dict, "MessageTimer.ShortSeconds", .many) self._MessageTimer_ShortSeconds_other = getValueWithForm(dict, "MessageTimer.ShortSeconds", .other) - self._ForwardedGifs_zero = getValueWithForm(dict, "ForwardedGifs", .zero) - self._ForwardedGifs_one = getValueWithForm(dict, "ForwardedGifs", .one) - self._ForwardedGifs_two = getValueWithForm(dict, "ForwardedGifs", .two) - self._ForwardedGifs_few = getValueWithForm(dict, "ForwardedGifs", .few) - self._ForwardedGifs_many = getValueWithForm(dict, "ForwardedGifs", .many) - self._ForwardedGifs_other = getValueWithForm(dict, "ForwardedGifs", .other) - self._MuteFor_Hours_zero = getValueWithForm(dict, "MuteFor.Hours", .zero) - self._MuteFor_Hours_one = getValueWithForm(dict, "MuteFor.Hours", .one) - self._MuteFor_Hours_two = getValueWithForm(dict, "MuteFor.Hours", .two) - self._MuteFor_Hours_few = getValueWithForm(dict, "MuteFor.Hours", .few) - self._MuteFor_Hours_many = getValueWithForm(dict, "MuteFor.Hours", .many) - self._MuteFor_Hours_other = getValueWithForm(dict, "MuteFor.Hours", .other) - self._StickerPack_StickerCount_zero = getValueWithForm(dict, "StickerPack.StickerCount", .zero) - self._StickerPack_StickerCount_one = getValueWithForm(dict, "StickerPack.StickerCount", .one) - self._StickerPack_StickerCount_two = getValueWithForm(dict, "StickerPack.StickerCount", .two) - self._StickerPack_StickerCount_few = getValueWithForm(dict, "StickerPack.StickerCount", .few) - self._StickerPack_StickerCount_many = getValueWithForm(dict, "StickerPack.StickerCount", .many) - self._StickerPack_StickerCount_other = getValueWithForm(dict, "StickerPack.StickerCount", .other) - self._Passport_Scans_zero = getValueWithForm(dict, "Passport.Scans", .zero) - self._Passport_Scans_one = getValueWithForm(dict, "Passport.Scans", .one) - self._Passport_Scans_two = getValueWithForm(dict, "Passport.Scans", .two) - self._Passport_Scans_few = getValueWithForm(dict, "Passport.Scans", .few) - self._Passport_Scans_many = getValueWithForm(dict, "Passport.Scans", .many) - self._Passport_Scans_other = getValueWithForm(dict, "Passport.Scans", .other) - self._Notification_GameScoreSelfSimple_zero = getValueWithForm(dict, "Notification.GameScoreSelfSimple", .zero) - self._Notification_GameScoreSelfSimple_one = getValueWithForm(dict, "Notification.GameScoreSelfSimple", .one) - self._Notification_GameScoreSelfSimple_two = getValueWithForm(dict, "Notification.GameScoreSelfSimple", .two) - self._Notification_GameScoreSelfSimple_few = getValueWithForm(dict, "Notification.GameScoreSelfSimple", .few) - self._Notification_GameScoreSelfSimple_many = getValueWithForm(dict, "Notification.GameScoreSelfSimple", .many) - self._Notification_GameScoreSelfSimple_other = getValueWithForm(dict, "Notification.GameScoreSelfSimple", .other) - self._ForwardedVideos_zero = getValueWithForm(dict, "ForwardedVideos", .zero) - self._ForwardedVideos_one = getValueWithForm(dict, "ForwardedVideos", .one) - self._ForwardedVideos_two = getValueWithForm(dict, "ForwardedVideos", .two) - self._ForwardedVideos_few = getValueWithForm(dict, "ForwardedVideos", .few) - self._ForwardedVideos_many = getValueWithForm(dict, "ForwardedVideos", .many) - self._ForwardedVideos_other = getValueWithForm(dict, "ForwardedVideos", .other) + self._AttachmentMenu_SendItem_zero = getValueWithForm(dict, "AttachmentMenu.SendItem", .zero) + self._AttachmentMenu_SendItem_one = getValueWithForm(dict, "AttachmentMenu.SendItem", .one) + self._AttachmentMenu_SendItem_two = getValueWithForm(dict, "AttachmentMenu.SendItem", .two) + self._AttachmentMenu_SendItem_few = getValueWithForm(dict, "AttachmentMenu.SendItem", .few) + self._AttachmentMenu_SendItem_many = getValueWithForm(dict, "AttachmentMenu.SendItem", .many) + self._AttachmentMenu_SendItem_other = getValueWithForm(dict, "AttachmentMenu.SendItem", .other) + self._SharedMedia_DeleteItemsConfirmation_zero = getValueWithForm(dict, "SharedMedia.DeleteItemsConfirmation", .zero) + self._SharedMedia_DeleteItemsConfirmation_one = getValueWithForm(dict, "SharedMedia.DeleteItemsConfirmation", .one) + self._SharedMedia_DeleteItemsConfirmation_two = getValueWithForm(dict, "SharedMedia.DeleteItemsConfirmation", .two) + self._SharedMedia_DeleteItemsConfirmation_few = getValueWithForm(dict, "SharedMedia.DeleteItemsConfirmation", .few) + self._SharedMedia_DeleteItemsConfirmation_many = getValueWithForm(dict, "SharedMedia.DeleteItemsConfirmation", .many) + self._SharedMedia_DeleteItemsConfirmation_other = getValueWithForm(dict, "SharedMedia.DeleteItemsConfirmation", .other) self._MessageTimer_ShortHours_zero = getValueWithForm(dict, "MessageTimer.ShortHours", .zero) self._MessageTimer_ShortHours_one = getValueWithForm(dict, "MessageTimer.ShortHours", .one) self._MessageTimer_ShortHours_two = getValueWithForm(dict, "MessageTimer.ShortHours", .two) self._MessageTimer_ShortHours_few = getValueWithForm(dict, "MessageTimer.ShortHours", .few) self._MessageTimer_ShortHours_many = getValueWithForm(dict, "MessageTimer.ShortHours", .many) self._MessageTimer_ShortHours_other = getValueWithForm(dict, "MessageTimer.ShortHours", .other) - self._ForwardedContacts_zero = getValueWithForm(dict, "ForwardedContacts", .zero) - self._ForwardedContacts_one = getValueWithForm(dict, "ForwardedContacts", .one) - self._ForwardedContacts_two = getValueWithForm(dict, "ForwardedContacts", .two) - self._ForwardedContacts_few = getValueWithForm(dict, "ForwardedContacts", .few) - self._ForwardedContacts_many = getValueWithForm(dict, "ForwardedContacts", .many) - self._ForwardedContacts_other = getValueWithForm(dict, "ForwardedContacts", .other) + self._MuteExpires_Days_zero = getValueWithForm(dict, "MuteExpires.Days", .zero) + self._MuteExpires_Days_one = getValueWithForm(dict, "MuteExpires.Days", .one) + self._MuteExpires_Days_two = getValueWithForm(dict, "MuteExpires.Days", .two) + self._MuteExpires_Days_few = getValueWithForm(dict, "MuteExpires.Days", .few) + self._MuteExpires_Days_many = getValueWithForm(dict, "MuteExpires.Days", .many) + self._MuteExpires_Days_other = getValueWithForm(dict, "MuteExpires.Days", .other) + self._Passport_Scans_zero = getValueWithForm(dict, "Passport.Scans", .zero) + self._Passport_Scans_one = getValueWithForm(dict, "Passport.Scans", .one) + self._Passport_Scans_two = getValueWithForm(dict, "Passport.Scans", .two) + self._Passport_Scans_few = getValueWithForm(dict, "Passport.Scans", .few) + self._Passport_Scans_many = getValueWithForm(dict, "Passport.Scans", .many) + self._Passport_Scans_other = getValueWithForm(dict, "Passport.Scans", .other) + self._MessageTimer_Hours_zero = getValueWithForm(dict, "MessageTimer.Hours", .zero) + self._MessageTimer_Hours_one = getValueWithForm(dict, "MessageTimer.Hours", .one) + self._MessageTimer_Hours_two = getValueWithForm(dict, "MessageTimer.Hours", .two) + self._MessageTimer_Hours_few = getValueWithForm(dict, "MessageTimer.Hours", .few) + self._MessageTimer_Hours_many = getValueWithForm(dict, "MessageTimer.Hours", .many) + self._MessageTimer_Hours_other = getValueWithForm(dict, "MessageTimer.Hours", .other) + self._Notification_GameScoreExtended_zero = getValueWithForm(dict, "Notification.GameScoreExtended", .zero) + self._Notification_GameScoreExtended_one = getValueWithForm(dict, "Notification.GameScoreExtended", .one) + self._Notification_GameScoreExtended_two = getValueWithForm(dict, "Notification.GameScoreExtended", .two) + self._Notification_GameScoreExtended_few = getValueWithForm(dict, "Notification.GameScoreExtended", .few) + self._Notification_GameScoreExtended_many = getValueWithForm(dict, "Notification.GameScoreExtended", .many) + self._Notification_GameScoreExtended_other = getValueWithForm(dict, "Notification.GameScoreExtended", .other) self._ForwardedLocations_zero = getValueWithForm(dict, "ForwardedLocations", .zero) self._ForwardedLocations_one = getValueWithForm(dict, "ForwardedLocations", .one) self._ForwardedLocations_two = getValueWithForm(dict, "ForwardedLocations", .two) self._ForwardedLocations_few = getValueWithForm(dict, "ForwardedLocations", .few) self._ForwardedLocations_many = getValueWithForm(dict, "ForwardedLocations", .many) self._ForwardedLocations_other = getValueWithForm(dict, "ForwardedLocations", .other) + self._ServiceMessage_GameScoreSelfSimple_zero = getValueWithForm(dict, "ServiceMessage.GameScoreSelfSimple", .zero) + self._ServiceMessage_GameScoreSelfSimple_one = getValueWithForm(dict, "ServiceMessage.GameScoreSelfSimple", .one) + self._ServiceMessage_GameScoreSelfSimple_two = getValueWithForm(dict, "ServiceMessage.GameScoreSelfSimple", .two) + self._ServiceMessage_GameScoreSelfSimple_few = getValueWithForm(dict, "ServiceMessage.GameScoreSelfSimple", .few) + self._ServiceMessage_GameScoreSelfSimple_many = getValueWithForm(dict, "ServiceMessage.GameScoreSelfSimple", .many) + self._ServiceMessage_GameScoreSelfSimple_other = getValueWithForm(dict, "ServiceMessage.GameScoreSelfSimple", .other) + self._ForwardedPhotos_zero = getValueWithForm(dict, "ForwardedPhotos", .zero) + self._ForwardedPhotos_one = getValueWithForm(dict, "ForwardedPhotos", .one) + self._ForwardedPhotos_two = getValueWithForm(dict, "ForwardedPhotos", .two) + self._ForwardedPhotos_few = getValueWithForm(dict, "ForwardedPhotos", .few) + self._ForwardedPhotos_many = getValueWithForm(dict, "ForwardedPhotos", .many) + self._ForwardedPhotos_other = getValueWithForm(dict, "ForwardedPhotos", .other) + self._LiveLocationUpdated_MinutesAgo_zero = getValueWithForm(dict, "LiveLocationUpdated.MinutesAgo", .zero) + self._LiveLocationUpdated_MinutesAgo_one = getValueWithForm(dict, "LiveLocationUpdated.MinutesAgo", .one) + self._LiveLocationUpdated_MinutesAgo_two = getValueWithForm(dict, "LiveLocationUpdated.MinutesAgo", .two) + self._LiveLocationUpdated_MinutesAgo_few = getValueWithForm(dict, "LiveLocationUpdated.MinutesAgo", .few) + self._LiveLocationUpdated_MinutesAgo_many = getValueWithForm(dict, "LiveLocationUpdated.MinutesAgo", .many) + self._LiveLocationUpdated_MinutesAgo_other = getValueWithForm(dict, "LiveLocationUpdated.MinutesAgo", .other) + self._StickerPack_RemoveMaskCount_zero = getValueWithForm(dict, "StickerPack.RemoveMaskCount", .zero) + self._StickerPack_RemoveMaskCount_one = getValueWithForm(dict, "StickerPack.RemoveMaskCount", .one) + self._StickerPack_RemoveMaskCount_two = getValueWithForm(dict, "StickerPack.RemoveMaskCount", .two) + self._StickerPack_RemoveMaskCount_few = getValueWithForm(dict, "StickerPack.RemoveMaskCount", .few) + self._StickerPack_RemoveMaskCount_many = getValueWithForm(dict, "StickerPack.RemoveMaskCount", .many) + self._StickerPack_RemoveMaskCount_other = getValueWithForm(dict, "StickerPack.RemoveMaskCount", .other) + self._SharedMedia_File_zero = getValueWithForm(dict, "SharedMedia.File", .zero) + self._SharedMedia_File_one = getValueWithForm(dict, "SharedMedia.File", .one) + self._SharedMedia_File_two = getValueWithForm(dict, "SharedMedia.File", .two) + self._SharedMedia_File_few = getValueWithForm(dict, "SharedMedia.File", .few) + self._SharedMedia_File_many = getValueWithForm(dict, "SharedMedia.File", .many) + self._SharedMedia_File_other = getValueWithForm(dict, "SharedMedia.File", .other) + self._MuteExpires_Hours_zero = getValueWithForm(dict, "MuteExpires.Hours", .zero) + self._MuteExpires_Hours_one = getValueWithForm(dict, "MuteExpires.Hours", .one) + self._MuteExpires_Hours_two = getValueWithForm(dict, "MuteExpires.Hours", .two) + self._MuteExpires_Hours_few = getValueWithForm(dict, "MuteExpires.Hours", .few) + self._MuteExpires_Hours_many = getValueWithForm(dict, "MuteExpires.Hours", .many) + self._MuteExpires_Hours_other = getValueWithForm(dict, "MuteExpires.Hours", .other) + self._MessageTimer_Seconds_zero = getValueWithForm(dict, "MessageTimer.Seconds", .zero) + self._MessageTimer_Seconds_one = getValueWithForm(dict, "MessageTimer.Seconds", .one) + self._MessageTimer_Seconds_two = getValueWithForm(dict, "MessageTimer.Seconds", .two) + self._MessageTimer_Seconds_few = getValueWithForm(dict, "MessageTimer.Seconds", .few) + self._MessageTimer_Seconds_many = getValueWithForm(dict, "MessageTimer.Seconds", .many) + self._MessageTimer_Seconds_other = getValueWithForm(dict, "MessageTimer.Seconds", .other) + self._Notifications_ExceptionMuteExpires_Hours_zero = getValueWithForm(dict, "Notifications.ExceptionMuteExpires.Hours", .zero) + self._Notifications_ExceptionMuteExpires_Hours_one = getValueWithForm(dict, "Notifications.ExceptionMuteExpires.Hours", .one) + self._Notifications_ExceptionMuteExpires_Hours_two = getValueWithForm(dict, "Notifications.ExceptionMuteExpires.Hours", .two) + self._Notifications_ExceptionMuteExpires_Hours_few = getValueWithForm(dict, "Notifications.ExceptionMuteExpires.Hours", .few) + self._Notifications_ExceptionMuteExpires_Hours_many = getValueWithForm(dict, "Notifications.ExceptionMuteExpires.Hours", .many) + self._Notifications_ExceptionMuteExpires_Hours_other = getValueWithForm(dict, "Notifications.ExceptionMuteExpires.Hours", .other) + self._MuteFor_Hours_zero = getValueWithForm(dict, "MuteFor.Hours", .zero) + self._MuteFor_Hours_one = getValueWithForm(dict, "MuteFor.Hours", .one) + self._MuteFor_Hours_two = getValueWithForm(dict, "MuteFor.Hours", .two) + self._MuteFor_Hours_few = getValueWithForm(dict, "MuteFor.Hours", .few) + self._MuteFor_Hours_many = getValueWithForm(dict, "MuteFor.Hours", .many) + self._MuteFor_Hours_other = getValueWithForm(dict, "MuteFor.Hours", .other) + self._MuteExpires_Minutes_zero = getValueWithForm(dict, "MuteExpires.Minutes", .zero) + self._MuteExpires_Minutes_one = getValueWithForm(dict, "MuteExpires.Minutes", .one) + self._MuteExpires_Minutes_two = getValueWithForm(dict, "MuteExpires.Minutes", .two) + self._MuteExpires_Minutes_few = getValueWithForm(dict, "MuteExpires.Minutes", .few) + self._MuteExpires_Minutes_many = getValueWithForm(dict, "MuteExpires.Minutes", .many) + self._MuteExpires_Minutes_other = getValueWithForm(dict, "MuteExpires.Minutes", .other) + self._MessageTimer_ShortWeeks_zero = getValueWithForm(dict, "MessageTimer.ShortWeeks", .zero) + self._MessageTimer_ShortWeeks_one = getValueWithForm(dict, "MessageTimer.ShortWeeks", .one) + self._MessageTimer_ShortWeeks_two = getValueWithForm(dict, "MessageTimer.ShortWeeks", .two) + self._MessageTimer_ShortWeeks_few = getValueWithForm(dict, "MessageTimer.ShortWeeks", .few) + self._MessageTimer_ShortWeeks_many = getValueWithForm(dict, "MessageTimer.ShortWeeks", .many) + self._MessageTimer_ShortWeeks_other = getValueWithForm(dict, "MessageTimer.ShortWeeks", .other) + self._AttachmentMenu_SendPhoto_zero = getValueWithForm(dict, "AttachmentMenu.SendPhoto", .zero) + self._AttachmentMenu_SendPhoto_one = getValueWithForm(dict, "AttachmentMenu.SendPhoto", .one) + self._AttachmentMenu_SendPhoto_two = getValueWithForm(dict, "AttachmentMenu.SendPhoto", .two) + self._AttachmentMenu_SendPhoto_few = getValueWithForm(dict, "AttachmentMenu.SendPhoto", .few) + self._AttachmentMenu_SendPhoto_many = getValueWithForm(dict, "AttachmentMenu.SendPhoto", .many) + self._AttachmentMenu_SendPhoto_other = getValueWithForm(dict, "AttachmentMenu.SendPhoto", .other) self._Notification_GameScoreSelfExtended_zero = getValueWithForm(dict, "Notification.GameScoreSelfExtended", .zero) self._Notification_GameScoreSelfExtended_one = getValueWithForm(dict, "Notification.GameScoreSelfExtended", .one) self._Notification_GameScoreSelfExtended_two = getValueWithForm(dict, "Notification.GameScoreSelfExtended", .two) @@ -8162,312 +8174,342 @@ public final class PresentationStrings { self._UserCount_few = getValueWithForm(dict, "UserCount", .few) self._UserCount_many = getValueWithForm(dict, "UserCount", .many) self._UserCount_other = getValueWithForm(dict, "UserCount", .other) - self._SharedMedia_Generic_zero = getValueWithForm(dict, "SharedMedia.Generic", .zero) - self._SharedMedia_Generic_one = getValueWithForm(dict, "SharedMedia.Generic", .one) - self._SharedMedia_Generic_two = getValueWithForm(dict, "SharedMedia.Generic", .two) - self._SharedMedia_Generic_few = getValueWithForm(dict, "SharedMedia.Generic", .few) - self._SharedMedia_Generic_many = getValueWithForm(dict, "SharedMedia.Generic", .many) - self._SharedMedia_Generic_other = getValueWithForm(dict, "SharedMedia.Generic", .other) - self._Call_Minutes_zero = getValueWithForm(dict, "Call.Minutes", .zero) - self._Call_Minutes_one = getValueWithForm(dict, "Call.Minutes", .one) - self._Call_Minutes_two = getValueWithForm(dict, "Call.Minutes", .two) - self._Call_Minutes_few = getValueWithForm(dict, "Call.Minutes", .few) - self._Call_Minutes_many = getValueWithForm(dict, "Call.Minutes", .many) - self._Call_Minutes_other = getValueWithForm(dict, "Call.Minutes", .other) - self._MessageTimer_ShortMinutes_zero = getValueWithForm(dict, "MessageTimer.ShortMinutes", .zero) - self._MessageTimer_ShortMinutes_one = getValueWithForm(dict, "MessageTimer.ShortMinutes", .one) - self._MessageTimer_ShortMinutes_two = getValueWithForm(dict, "MessageTimer.ShortMinutes", .two) - self._MessageTimer_ShortMinutes_few = getValueWithForm(dict, "MessageTimer.ShortMinutes", .few) - self._MessageTimer_ShortMinutes_many = getValueWithForm(dict, "MessageTimer.ShortMinutes", .many) - self._MessageTimer_ShortMinutes_other = getValueWithForm(dict, "MessageTimer.ShortMinutes", .other) - self._AttachmentMenu_SendVideo_zero = getValueWithForm(dict, "AttachmentMenu.SendVideo", .zero) - self._AttachmentMenu_SendVideo_one = getValueWithForm(dict, "AttachmentMenu.SendVideo", .one) - self._AttachmentMenu_SendVideo_two = getValueWithForm(dict, "AttachmentMenu.SendVideo", .two) - self._AttachmentMenu_SendVideo_few = getValueWithForm(dict, "AttachmentMenu.SendVideo", .few) - self._AttachmentMenu_SendVideo_many = getValueWithForm(dict, "AttachmentMenu.SendVideo", .many) - self._AttachmentMenu_SendVideo_other = getValueWithForm(dict, "AttachmentMenu.SendVideo", .other) - self._ForwardedMessages_zero = getValueWithForm(dict, "ForwardedMessages", .zero) - self._ForwardedMessages_one = getValueWithForm(dict, "ForwardedMessages", .one) - self._ForwardedMessages_two = getValueWithForm(dict, "ForwardedMessages", .two) - self._ForwardedMessages_few = getValueWithForm(dict, "ForwardedMessages", .few) - self._ForwardedMessages_many = getValueWithForm(dict, "ForwardedMessages", .many) - self._ForwardedMessages_other = getValueWithForm(dict, "ForwardedMessages", .other) - self._Conversation_StatusSubscribers_zero = getValueWithForm(dict, "Conversation.StatusSubscribers", .zero) - self._Conversation_StatusSubscribers_one = getValueWithForm(dict, "Conversation.StatusSubscribers", .one) - self._Conversation_StatusSubscribers_two = getValueWithForm(dict, "Conversation.StatusSubscribers", .two) - self._Conversation_StatusSubscribers_few = getValueWithForm(dict, "Conversation.StatusSubscribers", .few) - self._Conversation_StatusSubscribers_many = getValueWithForm(dict, "Conversation.StatusSubscribers", .many) - self._Conversation_StatusSubscribers_other = getValueWithForm(dict, "Conversation.StatusSubscribers", .other) - self._SharedMedia_Photo_zero = getValueWithForm(dict, "SharedMedia.Photo", .zero) - self._SharedMedia_Photo_one = getValueWithForm(dict, "SharedMedia.Photo", .one) - self._SharedMedia_Photo_two = getValueWithForm(dict, "SharedMedia.Photo", .two) - self._SharedMedia_Photo_few = getValueWithForm(dict, "SharedMedia.Photo", .few) - self._SharedMedia_Photo_many = getValueWithForm(dict, "SharedMedia.Photo", .many) - self._SharedMedia_Photo_other = getValueWithForm(dict, "SharedMedia.Photo", .other) - self._GroupInfo_ParticipantCount_zero = getValueWithForm(dict, "GroupInfo.ParticipantCount", .zero) - self._GroupInfo_ParticipantCount_one = getValueWithForm(dict, "GroupInfo.ParticipantCount", .one) - self._GroupInfo_ParticipantCount_two = getValueWithForm(dict, "GroupInfo.ParticipantCount", .two) - self._GroupInfo_ParticipantCount_few = getValueWithForm(dict, "GroupInfo.ParticipantCount", .few) - self._GroupInfo_ParticipantCount_many = getValueWithForm(dict, "GroupInfo.ParticipantCount", .many) - self._GroupInfo_ParticipantCount_other = getValueWithForm(dict, "GroupInfo.ParticipantCount", .other) - self._Watch_UserInfo_Mute_zero = getValueWithForm(dict, "Watch.UserInfo.Mute", .zero) - self._Watch_UserInfo_Mute_one = getValueWithForm(dict, "Watch.UserInfo.Mute", .one) - self._Watch_UserInfo_Mute_two = getValueWithForm(dict, "Watch.UserInfo.Mute", .two) - self._Watch_UserInfo_Mute_few = getValueWithForm(dict, "Watch.UserInfo.Mute", .few) - self._Watch_UserInfo_Mute_many = getValueWithForm(dict, "Watch.UserInfo.Mute", .many) - self._Watch_UserInfo_Mute_other = getValueWithForm(dict, "Watch.UserInfo.Mute", .other) - self._Forward_ConfirmMultipleFiles_zero = getValueWithForm(dict, "Forward.ConfirmMultipleFiles", .zero) - self._Forward_ConfirmMultipleFiles_one = getValueWithForm(dict, "Forward.ConfirmMultipleFiles", .one) - self._Forward_ConfirmMultipleFiles_two = getValueWithForm(dict, "Forward.ConfirmMultipleFiles", .two) - self._Forward_ConfirmMultipleFiles_few = getValueWithForm(dict, "Forward.ConfirmMultipleFiles", .few) - self._Forward_ConfirmMultipleFiles_many = getValueWithForm(dict, "Forward.ConfirmMultipleFiles", .many) - self._Forward_ConfirmMultipleFiles_other = getValueWithForm(dict, "Forward.ConfirmMultipleFiles", .other) - self._SharedMedia_Video_zero = getValueWithForm(dict, "SharedMedia.Video", .zero) - self._SharedMedia_Video_one = getValueWithForm(dict, "SharedMedia.Video", .one) - self._SharedMedia_Video_two = getValueWithForm(dict, "SharedMedia.Video", .two) - self._SharedMedia_Video_few = getValueWithForm(dict, "SharedMedia.Video", .few) - self._SharedMedia_Video_many = getValueWithForm(dict, "SharedMedia.Video", .many) - self._SharedMedia_Video_other = getValueWithForm(dict, "SharedMedia.Video", .other) - self._Call_ShortSeconds_zero = getValueWithForm(dict, "Call.ShortSeconds", .zero) - self._Call_ShortSeconds_one = getValueWithForm(dict, "Call.ShortSeconds", .one) - self._Call_ShortSeconds_two = getValueWithForm(dict, "Call.ShortSeconds", .two) - self._Call_ShortSeconds_few = getValueWithForm(dict, "Call.ShortSeconds", .few) - self._Call_ShortSeconds_many = getValueWithForm(dict, "Call.ShortSeconds", .many) - self._Call_ShortSeconds_other = getValueWithForm(dict, "Call.ShortSeconds", .other) - self._LiveLocationUpdated_MinutesAgo_zero = getValueWithForm(dict, "LiveLocationUpdated.MinutesAgo", .zero) - self._LiveLocationUpdated_MinutesAgo_one = getValueWithForm(dict, "LiveLocationUpdated.MinutesAgo", .one) - self._LiveLocationUpdated_MinutesAgo_two = getValueWithForm(dict, "LiveLocationUpdated.MinutesAgo", .two) - self._LiveLocationUpdated_MinutesAgo_few = getValueWithForm(dict, "LiveLocationUpdated.MinutesAgo", .few) - self._LiveLocationUpdated_MinutesAgo_many = getValueWithForm(dict, "LiveLocationUpdated.MinutesAgo", .many) - self._LiveLocationUpdated_MinutesAgo_other = getValueWithForm(dict, "LiveLocationUpdated.MinutesAgo", .other) - self._MuteExpires_Hours_zero = getValueWithForm(dict, "MuteExpires.Hours", .zero) - self._MuteExpires_Hours_one = getValueWithForm(dict, "MuteExpires.Hours", .one) - self._MuteExpires_Hours_two = getValueWithForm(dict, "MuteExpires.Hours", .two) - self._MuteExpires_Hours_few = getValueWithForm(dict, "MuteExpires.Hours", .few) - self._MuteExpires_Hours_many = getValueWithForm(dict, "MuteExpires.Hours", .many) - self._MuteExpires_Hours_other = getValueWithForm(dict, "MuteExpires.Hours", .other) - self._SharedMedia_DeleteItemsConfirmation_zero = getValueWithForm(dict, "SharedMedia.DeleteItemsConfirmation", .zero) - self._SharedMedia_DeleteItemsConfirmation_one = getValueWithForm(dict, "SharedMedia.DeleteItemsConfirmation", .one) - self._SharedMedia_DeleteItemsConfirmation_two = getValueWithForm(dict, "SharedMedia.DeleteItemsConfirmation", .two) - self._SharedMedia_DeleteItemsConfirmation_few = getValueWithForm(dict, "SharedMedia.DeleteItemsConfirmation", .few) - self._SharedMedia_DeleteItemsConfirmation_many = getValueWithForm(dict, "SharedMedia.DeleteItemsConfirmation", .many) - self._SharedMedia_DeleteItemsConfirmation_other = getValueWithForm(dict, "SharedMedia.DeleteItemsConfirmation", .other) - self._Conversation_StatusMembers_zero = getValueWithForm(dict, "Conversation.StatusMembers", .zero) - self._Conversation_StatusMembers_one = getValueWithForm(dict, "Conversation.StatusMembers", .one) - self._Conversation_StatusMembers_two = getValueWithForm(dict, "Conversation.StatusMembers", .two) - self._Conversation_StatusMembers_few = getValueWithForm(dict, "Conversation.StatusMembers", .few) - self._Conversation_StatusMembers_many = getValueWithForm(dict, "Conversation.StatusMembers", .many) - self._Conversation_StatusMembers_other = getValueWithForm(dict, "Conversation.StatusMembers", .other) - self._MessageTimer_Seconds_zero = getValueWithForm(dict, "MessageTimer.Seconds", .zero) - self._MessageTimer_Seconds_one = getValueWithForm(dict, "MessageTimer.Seconds", .one) - self._MessageTimer_Seconds_two = getValueWithForm(dict, "MessageTimer.Seconds", .two) - self._MessageTimer_Seconds_few = getValueWithForm(dict, "MessageTimer.Seconds", .few) - self._MessageTimer_Seconds_many = getValueWithForm(dict, "MessageTimer.Seconds", .many) - self._MessageTimer_Seconds_other = getValueWithForm(dict, "MessageTimer.Seconds", .other) - self._Watch_LastSeen_MinutesAgo_zero = getValueWithForm(dict, "Watch.LastSeen.MinutesAgo", .zero) - self._Watch_LastSeen_MinutesAgo_one = getValueWithForm(dict, "Watch.LastSeen.MinutesAgo", .one) - self._Watch_LastSeen_MinutesAgo_two = getValueWithForm(dict, "Watch.LastSeen.MinutesAgo", .two) - self._Watch_LastSeen_MinutesAgo_few = getValueWithForm(dict, "Watch.LastSeen.MinutesAgo", .few) - self._Watch_LastSeen_MinutesAgo_many = getValueWithForm(dict, "Watch.LastSeen.MinutesAgo", .many) - self._Watch_LastSeen_MinutesAgo_other = getValueWithForm(dict, "Watch.LastSeen.MinutesAgo", .other) - self._LastSeen_HoursAgo_zero = getValueWithForm(dict, "LastSeen.HoursAgo", .zero) - self._LastSeen_HoursAgo_one = getValueWithForm(dict, "LastSeen.HoursAgo", .one) - self._LastSeen_HoursAgo_two = getValueWithForm(dict, "LastSeen.HoursAgo", .two) - self._LastSeen_HoursAgo_few = getValueWithForm(dict, "LastSeen.HoursAgo", .few) - self._LastSeen_HoursAgo_many = getValueWithForm(dict, "LastSeen.HoursAgo", .many) - self._LastSeen_HoursAgo_other = getValueWithForm(dict, "LastSeen.HoursAgo", .other) - self._Media_ShareItem_zero = getValueWithForm(dict, "Media.ShareItem", .zero) - self._Media_ShareItem_one = getValueWithForm(dict, "Media.ShareItem", .one) - self._Media_ShareItem_two = getValueWithForm(dict, "Media.ShareItem", .two) - self._Media_ShareItem_few = getValueWithForm(dict, "Media.ShareItem", .few) - self._Media_ShareItem_many = getValueWithForm(dict, "Media.ShareItem", .many) - self._Media_ShareItem_other = getValueWithForm(dict, "Media.ShareItem", .other) - self._QuickSend_Photos_zero = getValueWithForm(dict, "QuickSend.Photos", .zero) - self._QuickSend_Photos_one = getValueWithForm(dict, "QuickSend.Photos", .one) - self._QuickSend_Photos_two = getValueWithForm(dict, "QuickSend.Photos", .two) - self._QuickSend_Photos_few = getValueWithForm(dict, "QuickSend.Photos", .few) - self._QuickSend_Photos_many = getValueWithForm(dict, "QuickSend.Photos", .many) - self._QuickSend_Photos_other = getValueWithForm(dict, "QuickSend.Photos", .other) - self._Media_SharePhoto_zero = getValueWithForm(dict, "Media.SharePhoto", .zero) - self._Media_SharePhoto_one = getValueWithForm(dict, "Media.SharePhoto", .one) - self._Media_SharePhoto_two = getValueWithForm(dict, "Media.SharePhoto", .two) - self._Media_SharePhoto_few = getValueWithForm(dict, "Media.SharePhoto", .few) - self._Media_SharePhoto_many = getValueWithForm(dict, "Media.SharePhoto", .many) - self._Media_SharePhoto_other = getValueWithForm(dict, "Media.SharePhoto", .other) - self._MuteExpires_Minutes_zero = getValueWithForm(dict, "MuteExpires.Minutes", .zero) - self._MuteExpires_Minutes_one = getValueWithForm(dict, "MuteExpires.Minutes", .one) - self._MuteExpires_Minutes_two = getValueWithForm(dict, "MuteExpires.Minutes", .two) - self._MuteExpires_Minutes_few = getValueWithForm(dict, "MuteExpires.Minutes", .few) - self._MuteExpires_Minutes_many = getValueWithForm(dict, "MuteExpires.Minutes", .many) - self._MuteExpires_Minutes_other = getValueWithForm(dict, "MuteExpires.Minutes", .other) - self._Notification_GameScoreSimple_zero = getValueWithForm(dict, "Notification.GameScoreSimple", .zero) - self._Notification_GameScoreSimple_one = getValueWithForm(dict, "Notification.GameScoreSimple", .one) - self._Notification_GameScoreSimple_two = getValueWithForm(dict, "Notification.GameScoreSimple", .two) - self._Notification_GameScoreSimple_few = getValueWithForm(dict, "Notification.GameScoreSimple", .few) - self._Notification_GameScoreSimple_many = getValueWithForm(dict, "Notification.GameScoreSimple", .many) - self._Notification_GameScoreSimple_other = getValueWithForm(dict, "Notification.GameScoreSimple", .other) - self._AttachmentMenu_SendItem_zero = getValueWithForm(dict, "AttachmentMenu.SendItem", .zero) - self._AttachmentMenu_SendItem_one = getValueWithForm(dict, "AttachmentMenu.SendItem", .one) - self._AttachmentMenu_SendItem_two = getValueWithForm(dict, "AttachmentMenu.SendItem", .two) - self._AttachmentMenu_SendItem_few = getValueWithForm(dict, "AttachmentMenu.SendItem", .few) - self._AttachmentMenu_SendItem_many = getValueWithForm(dict, "AttachmentMenu.SendItem", .many) - self._AttachmentMenu_SendItem_other = getValueWithForm(dict, "AttachmentMenu.SendItem", .other) - self._MessageTimer_Years_zero = getValueWithForm(dict, "MessageTimer.Years", .zero) - self._MessageTimer_Years_one = getValueWithForm(dict, "MessageTimer.Years", .one) - self._MessageTimer_Years_two = getValueWithForm(dict, "MessageTimer.Years", .two) - self._MessageTimer_Years_few = getValueWithForm(dict, "MessageTimer.Years", .few) - self._MessageTimer_Years_many = getValueWithForm(dict, "MessageTimer.Years", .many) - self._MessageTimer_Years_other = getValueWithForm(dict, "MessageTimer.Years", .other) - self._PrivacyLastSeenSettings_AddUsers_zero = getValueWithForm(dict, "PrivacyLastSeenSettings.AddUsers", .zero) - self._PrivacyLastSeenSettings_AddUsers_one = getValueWithForm(dict, "PrivacyLastSeenSettings.AddUsers", .one) - self._PrivacyLastSeenSettings_AddUsers_two = getValueWithForm(dict, "PrivacyLastSeenSettings.AddUsers", .two) - self._PrivacyLastSeenSettings_AddUsers_few = getValueWithForm(dict, "PrivacyLastSeenSettings.AddUsers", .few) - self._PrivacyLastSeenSettings_AddUsers_many = getValueWithForm(dict, "PrivacyLastSeenSettings.AddUsers", .many) - self._PrivacyLastSeenSettings_AddUsers_other = getValueWithForm(dict, "PrivacyLastSeenSettings.AddUsers", .other) - self._AttachmentMenu_SendGif_zero = getValueWithForm(dict, "AttachmentMenu.SendGif", .zero) - self._AttachmentMenu_SendGif_one = getValueWithForm(dict, "AttachmentMenu.SendGif", .one) - self._AttachmentMenu_SendGif_two = getValueWithForm(dict, "AttachmentMenu.SendGif", .two) - self._AttachmentMenu_SendGif_few = getValueWithForm(dict, "AttachmentMenu.SendGif", .few) - self._AttachmentMenu_SendGif_many = getValueWithForm(dict, "AttachmentMenu.SendGif", .many) - self._AttachmentMenu_SendGif_other = getValueWithForm(dict, "AttachmentMenu.SendGif", .other) - self._ForwardedVideoMessages_zero = getValueWithForm(dict, "ForwardedVideoMessages", .zero) - self._ForwardedVideoMessages_one = getValueWithForm(dict, "ForwardedVideoMessages", .one) - self._ForwardedVideoMessages_two = getValueWithForm(dict, "ForwardedVideoMessages", .two) - self._ForwardedVideoMessages_few = getValueWithForm(dict, "ForwardedVideoMessages", .few) - self._ForwardedVideoMessages_many = getValueWithForm(dict, "ForwardedVideoMessages", .many) - self._ForwardedVideoMessages_other = getValueWithForm(dict, "ForwardedVideoMessages", .other) - self._Media_ShareVideo_zero = getValueWithForm(dict, "Media.ShareVideo", .zero) - self._Media_ShareVideo_one = getValueWithForm(dict, "Media.ShareVideo", .one) - self._Media_ShareVideo_two = getValueWithForm(dict, "Media.ShareVideo", .two) - self._Media_ShareVideo_few = getValueWithForm(dict, "Media.ShareVideo", .few) - self._Media_ShareVideo_many = getValueWithForm(dict, "Media.ShareVideo", .many) - self._Media_ShareVideo_other = getValueWithForm(dict, "Media.ShareVideo", .other) - self._StickerPack_RemoveStickerCount_zero = getValueWithForm(dict, "StickerPack.RemoveStickerCount", .zero) - self._StickerPack_RemoveStickerCount_one = getValueWithForm(dict, "StickerPack.RemoveStickerCount", .one) - self._StickerPack_RemoveStickerCount_two = getValueWithForm(dict, "StickerPack.RemoveStickerCount", .two) - self._StickerPack_RemoveStickerCount_few = getValueWithForm(dict, "StickerPack.RemoveStickerCount", .few) - self._StickerPack_RemoveStickerCount_many = getValueWithForm(dict, "StickerPack.RemoveStickerCount", .many) - self._StickerPack_RemoveStickerCount_other = getValueWithForm(dict, "StickerPack.RemoveStickerCount", .other) - self._Call_Seconds_zero = getValueWithForm(dict, "Call.Seconds", .zero) - self._Call_Seconds_one = getValueWithForm(dict, "Call.Seconds", .one) - self._Call_Seconds_two = getValueWithForm(dict, "Call.Seconds", .two) - self._Call_Seconds_few = getValueWithForm(dict, "Call.Seconds", .few) - self._Call_Seconds_many = getValueWithForm(dict, "Call.Seconds", .many) - self._Call_Seconds_other = getValueWithForm(dict, "Call.Seconds", .other) - self._MessageTimer_Hours_zero = getValueWithForm(dict, "MessageTimer.Hours", .zero) - self._MessageTimer_Hours_one = getValueWithForm(dict, "MessageTimer.Hours", .one) - self._MessageTimer_Hours_two = getValueWithForm(dict, "MessageTimer.Hours", .two) - self._MessageTimer_Hours_few = getValueWithForm(dict, "MessageTimer.Hours", .few) - self._MessageTimer_Hours_many = getValueWithForm(dict, "MessageTimer.Hours", .many) - self._MessageTimer_Hours_other = getValueWithForm(dict, "MessageTimer.Hours", .other) - self._Conversation_StatusOnline_zero = getValueWithForm(dict, "Conversation.StatusOnline", .zero) - self._Conversation_StatusOnline_one = getValueWithForm(dict, "Conversation.StatusOnline", .one) - self._Conversation_StatusOnline_two = getValueWithForm(dict, "Conversation.StatusOnline", .two) - self._Conversation_StatusOnline_few = getValueWithForm(dict, "Conversation.StatusOnline", .few) - self._Conversation_StatusOnline_many = getValueWithForm(dict, "Conversation.StatusOnline", .many) - self._Conversation_StatusOnline_other = getValueWithForm(dict, "Conversation.StatusOnline", .other) - self._ForwardedPhotos_zero = getValueWithForm(dict, "ForwardedPhotos", .zero) - self._ForwardedPhotos_one = getValueWithForm(dict, "ForwardedPhotos", .one) - self._ForwardedPhotos_two = getValueWithForm(dict, "ForwardedPhotos", .two) - self._ForwardedPhotos_few = getValueWithForm(dict, "ForwardedPhotos", .few) - self._ForwardedPhotos_many = getValueWithForm(dict, "ForwardedPhotos", .many) - self._ForwardedPhotos_other = getValueWithForm(dict, "ForwardedPhotos", .other) - self._MessageTimer_Weeks_zero = getValueWithForm(dict, "MessageTimer.Weeks", .zero) - self._MessageTimer_Weeks_one = getValueWithForm(dict, "MessageTimer.Weeks", .one) - self._MessageTimer_Weeks_two = getValueWithForm(dict, "MessageTimer.Weeks", .two) - self._MessageTimer_Weeks_few = getValueWithForm(dict, "MessageTimer.Weeks", .few) - self._MessageTimer_Weeks_many = getValueWithForm(dict, "MessageTimer.Weeks", .many) - self._MessageTimer_Weeks_other = getValueWithForm(dict, "MessageTimer.Weeks", .other) - self._Call_ShortMinutes_zero = getValueWithForm(dict, "Call.ShortMinutes", .zero) - self._Call_ShortMinutes_one = getValueWithForm(dict, "Call.ShortMinutes", .one) - self._Call_ShortMinutes_two = getValueWithForm(dict, "Call.ShortMinutes", .two) - self._Call_ShortMinutes_few = getValueWithForm(dict, "Call.ShortMinutes", .few) - self._Call_ShortMinutes_many = getValueWithForm(dict, "Call.ShortMinutes", .many) - self._Call_ShortMinutes_other = getValueWithForm(dict, "Call.ShortMinutes", .other) self._Notifications_ExceptionMuteExpires_Days_zero = getValueWithForm(dict, "Notifications.ExceptionMuteExpires.Days", .zero) self._Notifications_ExceptionMuteExpires_Days_one = getValueWithForm(dict, "Notifications.ExceptionMuteExpires.Days", .one) self._Notifications_ExceptionMuteExpires_Days_two = getValueWithForm(dict, "Notifications.ExceptionMuteExpires.Days", .two) self._Notifications_ExceptionMuteExpires_Days_few = getValueWithForm(dict, "Notifications.ExceptionMuteExpires.Days", .few) self._Notifications_ExceptionMuteExpires_Days_many = getValueWithForm(dict, "Notifications.ExceptionMuteExpires.Days", .many) self._Notifications_ExceptionMuteExpires_Days_other = getValueWithForm(dict, "Notifications.ExceptionMuteExpires.Days", .other) - self._ForwardedAudios_zero = getValueWithForm(dict, "ForwardedAudios", .zero) - self._ForwardedAudios_one = getValueWithForm(dict, "ForwardedAudios", .one) - self._ForwardedAudios_two = getValueWithForm(dict, "ForwardedAudios", .two) - self._ForwardedAudios_few = getValueWithForm(dict, "ForwardedAudios", .few) - self._ForwardedAudios_many = getValueWithForm(dict, "ForwardedAudios", .many) - self._ForwardedAudios_other = getValueWithForm(dict, "ForwardedAudios", .other) - self._Conversation_LiveLocationMembersCount_zero = getValueWithForm(dict, "Conversation.LiveLocationMembersCount", .zero) - self._Conversation_LiveLocationMembersCount_one = getValueWithForm(dict, "Conversation.LiveLocationMembersCount", .one) - self._Conversation_LiveLocationMembersCount_two = getValueWithForm(dict, "Conversation.LiveLocationMembersCount", .two) - self._Conversation_LiveLocationMembersCount_few = getValueWithForm(dict, "Conversation.LiveLocationMembersCount", .few) - self._Conversation_LiveLocationMembersCount_many = getValueWithForm(dict, "Conversation.LiveLocationMembersCount", .many) - self._Conversation_LiveLocationMembersCount_other = getValueWithForm(dict, "Conversation.LiveLocationMembersCount", .other) - self._StickerPack_AddStickerCount_zero = getValueWithForm(dict, "StickerPack.AddStickerCount", .zero) - self._StickerPack_AddStickerCount_one = getValueWithForm(dict, "StickerPack.AddStickerCount", .one) - self._StickerPack_AddStickerCount_two = getValueWithForm(dict, "StickerPack.AddStickerCount", .two) - self._StickerPack_AddStickerCount_few = getValueWithForm(dict, "StickerPack.AddStickerCount", .few) - self._StickerPack_AddStickerCount_many = getValueWithForm(dict, "StickerPack.AddStickerCount", .many) - self._StickerPack_AddStickerCount_other = getValueWithForm(dict, "StickerPack.AddStickerCount", .other) - self._Contacts_ImportersCount_zero = getValueWithForm(dict, "Contacts.ImportersCount", .zero) - self._Contacts_ImportersCount_one = getValueWithForm(dict, "Contacts.ImportersCount", .one) - self._Contacts_ImportersCount_two = getValueWithForm(dict, "Contacts.ImportersCount", .two) - self._Contacts_ImportersCount_few = getValueWithForm(dict, "Contacts.ImportersCount", .few) - self._Contacts_ImportersCount_many = getValueWithForm(dict, "Contacts.ImportersCount", .many) - self._Contacts_ImportersCount_other = getValueWithForm(dict, "Contacts.ImportersCount", .other) - self._StickerPack_RemoveMaskCount_zero = getValueWithForm(dict, "StickerPack.RemoveMaskCount", .zero) - self._StickerPack_RemoveMaskCount_one = getValueWithForm(dict, "StickerPack.RemoveMaskCount", .one) - self._StickerPack_RemoveMaskCount_two = getValueWithForm(dict, "StickerPack.RemoveMaskCount", .two) - self._StickerPack_RemoveMaskCount_few = getValueWithForm(dict, "StickerPack.RemoveMaskCount", .few) - self._StickerPack_RemoveMaskCount_many = getValueWithForm(dict, "StickerPack.RemoveMaskCount", .many) - self._StickerPack_RemoveMaskCount_other = getValueWithForm(dict, "StickerPack.RemoveMaskCount", .other) - self._Notifications_ExceptionMuteExpires_Minutes_zero = getValueWithForm(dict, "Notifications.ExceptionMuteExpires.Minutes", .zero) - self._Notifications_ExceptionMuteExpires_Minutes_one = getValueWithForm(dict, "Notifications.ExceptionMuteExpires.Minutes", .one) - self._Notifications_ExceptionMuteExpires_Minutes_two = getValueWithForm(dict, "Notifications.ExceptionMuteExpires.Minutes", .two) - self._Notifications_ExceptionMuteExpires_Minutes_few = getValueWithForm(dict, "Notifications.ExceptionMuteExpires.Minutes", .few) - self._Notifications_ExceptionMuteExpires_Minutes_many = getValueWithForm(dict, "Notifications.ExceptionMuteExpires.Minutes", .many) - self._Notifications_ExceptionMuteExpires_Minutes_other = getValueWithForm(dict, "Notifications.ExceptionMuteExpires.Minutes", .other) - self._InviteText_ContactsCount_zero = getValueWithForm(dict, "InviteText.ContactsCount", .zero) - self._InviteText_ContactsCount_one = getValueWithForm(dict, "InviteText.ContactsCount", .one) - self._InviteText_ContactsCount_two = getValueWithForm(dict, "InviteText.ContactsCount", .two) - self._InviteText_ContactsCount_few = getValueWithForm(dict, "InviteText.ContactsCount", .few) - self._InviteText_ContactsCount_many = getValueWithForm(dict, "InviteText.ContactsCount", .many) - self._InviteText_ContactsCount_other = getValueWithForm(dict, "InviteText.ContactsCount", .other) + self._Notifications_Exceptions_zero = getValueWithForm(dict, "Notifications.Exceptions", .zero) + self._Notifications_Exceptions_one = getValueWithForm(dict, "Notifications.Exceptions", .one) + self._Notifications_Exceptions_two = getValueWithForm(dict, "Notifications.Exceptions", .two) + self._Notifications_Exceptions_few = getValueWithForm(dict, "Notifications.Exceptions", .few) + self._Notifications_Exceptions_many = getValueWithForm(dict, "Notifications.Exceptions", .many) + self._Notifications_Exceptions_other = getValueWithForm(dict, "Notifications.Exceptions", .other) + self._StickerPack_RemoveStickerCount_zero = getValueWithForm(dict, "StickerPack.RemoveStickerCount", .zero) + self._StickerPack_RemoveStickerCount_one = getValueWithForm(dict, "StickerPack.RemoveStickerCount", .one) + self._StickerPack_RemoveStickerCount_two = getValueWithForm(dict, "StickerPack.RemoveStickerCount", .two) + self._StickerPack_RemoveStickerCount_few = getValueWithForm(dict, "StickerPack.RemoveStickerCount", .few) + self._StickerPack_RemoveStickerCount_many = getValueWithForm(dict, "StickerPack.RemoveStickerCount", .many) + self._StickerPack_RemoveStickerCount_other = getValueWithForm(dict, "StickerPack.RemoveStickerCount", .other) + self._MessageTimer_Weeks_zero = getValueWithForm(dict, "MessageTimer.Weeks", .zero) + self._MessageTimer_Weeks_one = getValueWithForm(dict, "MessageTimer.Weeks", .one) + self._MessageTimer_Weeks_two = getValueWithForm(dict, "MessageTimer.Weeks", .two) + self._MessageTimer_Weeks_few = getValueWithForm(dict, "MessageTimer.Weeks", .few) + self._MessageTimer_Weeks_many = getValueWithForm(dict, "MessageTimer.Weeks", .many) + self._MessageTimer_Weeks_other = getValueWithForm(dict, "MessageTimer.Weeks", .other) + self._ForwardedContacts_zero = getValueWithForm(dict, "ForwardedContacts", .zero) + self._ForwardedContacts_one = getValueWithForm(dict, "ForwardedContacts", .one) + self._ForwardedContacts_two = getValueWithForm(dict, "ForwardedContacts", .two) + self._ForwardedContacts_few = getValueWithForm(dict, "ForwardedContacts", .few) + self._ForwardedContacts_many = getValueWithForm(dict, "ForwardedContacts", .many) + self._ForwardedContacts_other = getValueWithForm(dict, "ForwardedContacts", .other) + self._Media_ShareItem_zero = getValueWithForm(dict, "Media.ShareItem", .zero) + self._Media_ShareItem_one = getValueWithForm(dict, "Media.ShareItem", .one) + self._Media_ShareItem_two = getValueWithForm(dict, "Media.ShareItem", .two) + self._Media_ShareItem_few = getValueWithForm(dict, "Media.ShareItem", .few) + self._Media_ShareItem_many = getValueWithForm(dict, "Media.ShareItem", .many) + self._Media_ShareItem_other = getValueWithForm(dict, "Media.ShareItem", .other) + self._MessageTimer_ShortDays_zero = getValueWithForm(dict, "MessageTimer.ShortDays", .zero) + self._MessageTimer_ShortDays_one = getValueWithForm(dict, "MessageTimer.ShortDays", .one) + self._MessageTimer_ShortDays_two = getValueWithForm(dict, "MessageTimer.ShortDays", .two) + self._MessageTimer_ShortDays_few = getValueWithForm(dict, "MessageTimer.ShortDays", .few) + self._MessageTimer_ShortDays_many = getValueWithForm(dict, "MessageTimer.ShortDays", .many) + self._MessageTimer_ShortDays_other = getValueWithForm(dict, "MessageTimer.ShortDays", .other) + self._Forward_ConfirmMultipleFiles_zero = getValueWithForm(dict, "Forward.ConfirmMultipleFiles", .zero) + self._Forward_ConfirmMultipleFiles_one = getValueWithForm(dict, "Forward.ConfirmMultipleFiles", .one) + self._Forward_ConfirmMultipleFiles_two = getValueWithForm(dict, "Forward.ConfirmMultipleFiles", .two) + self._Forward_ConfirmMultipleFiles_few = getValueWithForm(dict, "Forward.ConfirmMultipleFiles", .few) + self._Forward_ConfirmMultipleFiles_many = getValueWithForm(dict, "Forward.ConfirmMultipleFiles", .many) + self._Forward_ConfirmMultipleFiles_other = getValueWithForm(dict, "Forward.ConfirmMultipleFiles", .other) + self._Map_ETAHours_zero = getValueWithForm(dict, "Map.ETAHours", .zero) + self._Map_ETAHours_one = getValueWithForm(dict, "Map.ETAHours", .one) + self._Map_ETAHours_two = getValueWithForm(dict, "Map.ETAHours", .two) + self._Map_ETAHours_few = getValueWithForm(dict, "Map.ETAHours", .few) + self._Map_ETAHours_many = getValueWithForm(dict, "Map.ETAHours", .many) + self._Map_ETAHours_other = getValueWithForm(dict, "Map.ETAHours", .other) + self._ServiceMessage_GameScoreExtended_zero = getValueWithForm(dict, "ServiceMessage.GameScoreExtended", .zero) + self._ServiceMessage_GameScoreExtended_one = getValueWithForm(dict, "ServiceMessage.GameScoreExtended", .one) + self._ServiceMessage_GameScoreExtended_two = getValueWithForm(dict, "ServiceMessage.GameScoreExtended", .two) + self._ServiceMessage_GameScoreExtended_few = getValueWithForm(dict, "ServiceMessage.GameScoreExtended", .few) + self._ServiceMessage_GameScoreExtended_many = getValueWithForm(dict, "ServiceMessage.GameScoreExtended", .many) + self._ServiceMessage_GameScoreExtended_other = getValueWithForm(dict, "ServiceMessage.GameScoreExtended", .other) + self._ForwardedGifs_zero = getValueWithForm(dict, "ForwardedGifs", .zero) + self._ForwardedGifs_one = getValueWithForm(dict, "ForwardedGifs", .one) + self._ForwardedGifs_two = getValueWithForm(dict, "ForwardedGifs", .two) + self._ForwardedGifs_few = getValueWithForm(dict, "ForwardedGifs", .few) + self._ForwardedGifs_many = getValueWithForm(dict, "ForwardedGifs", .many) + self._ForwardedGifs_other = getValueWithForm(dict, "ForwardedGifs", .other) + self._Media_ShareVideo_zero = getValueWithForm(dict, "Media.ShareVideo", .zero) + self._Media_ShareVideo_one = getValueWithForm(dict, "Media.ShareVideo", .one) + self._Media_ShareVideo_two = getValueWithForm(dict, "Media.ShareVideo", .two) + self._Media_ShareVideo_few = getValueWithForm(dict, "Media.ShareVideo", .few) + self._Media_ShareVideo_many = getValueWithForm(dict, "Media.ShareVideo", .many) + self._Media_ShareVideo_other = getValueWithForm(dict, "Media.ShareVideo", .other) + self._SharedMedia_Video_zero = getValueWithForm(dict, "SharedMedia.Video", .zero) + self._SharedMedia_Video_one = getValueWithForm(dict, "SharedMedia.Video", .one) + self._SharedMedia_Video_two = getValueWithForm(dict, "SharedMedia.Video", .two) + self._SharedMedia_Video_few = getValueWithForm(dict, "SharedMedia.Video", .few) + self._SharedMedia_Video_many = getValueWithForm(dict, "SharedMedia.Video", .many) + self._SharedMedia_Video_other = getValueWithForm(dict, "SharedMedia.Video", .other) + self._PasscodeSettings_FailedAttempts_zero = getValueWithForm(dict, "PasscodeSettings.FailedAttempts", .zero) + self._PasscodeSettings_FailedAttempts_one = getValueWithForm(dict, "PasscodeSettings.FailedAttempts", .one) + self._PasscodeSettings_FailedAttempts_two = getValueWithForm(dict, "PasscodeSettings.FailedAttempts", .two) + self._PasscodeSettings_FailedAttempts_few = getValueWithForm(dict, "PasscodeSettings.FailedAttempts", .few) + self._PasscodeSettings_FailedAttempts_many = getValueWithForm(dict, "PasscodeSettings.FailedAttempts", .many) + self._PasscodeSettings_FailedAttempts_other = getValueWithForm(dict, "PasscodeSettings.FailedAttempts", .other) + self._QuickSend_Photos_zero = getValueWithForm(dict, "QuickSend.Photos", .zero) + self._QuickSend_Photos_one = getValueWithForm(dict, "QuickSend.Photos", .one) + self._QuickSend_Photos_two = getValueWithForm(dict, "QuickSend.Photos", .two) + self._QuickSend_Photos_few = getValueWithForm(dict, "QuickSend.Photos", .few) + self._QuickSend_Photos_many = getValueWithForm(dict, "QuickSend.Photos", .many) + self._QuickSend_Photos_other = getValueWithForm(dict, "QuickSend.Photos", .other) + self._Watch_LastSeen_HoursAgo_zero = getValueWithForm(dict, "Watch.LastSeen.HoursAgo", .zero) + self._Watch_LastSeen_HoursAgo_one = getValueWithForm(dict, "Watch.LastSeen.HoursAgo", .one) + self._Watch_LastSeen_HoursAgo_two = getValueWithForm(dict, "Watch.LastSeen.HoursAgo", .two) + self._Watch_LastSeen_HoursAgo_few = getValueWithForm(dict, "Watch.LastSeen.HoursAgo", .few) + self._Watch_LastSeen_HoursAgo_many = getValueWithForm(dict, "Watch.LastSeen.HoursAgo", .many) + self._Watch_LastSeen_HoursAgo_other = getValueWithForm(dict, "Watch.LastSeen.HoursAgo", .other) + self._AttachmentMenu_SendGif_zero = getValueWithForm(dict, "AttachmentMenu.SendGif", .zero) + self._AttachmentMenu_SendGif_one = getValueWithForm(dict, "AttachmentMenu.SendGif", .one) + self._AttachmentMenu_SendGif_two = getValueWithForm(dict, "AttachmentMenu.SendGif", .two) + self._AttachmentMenu_SendGif_few = getValueWithForm(dict, "AttachmentMenu.SendGif", .few) + self._AttachmentMenu_SendGif_many = getValueWithForm(dict, "AttachmentMenu.SendGif", .many) + self._AttachmentMenu_SendGif_other = getValueWithForm(dict, "AttachmentMenu.SendGif", .other) + self._Conversation_StatusSubscribers_zero = getValueWithForm(dict, "Conversation.StatusSubscribers", .zero) + self._Conversation_StatusSubscribers_one = getValueWithForm(dict, "Conversation.StatusSubscribers", .one) + self._Conversation_StatusSubscribers_two = getValueWithForm(dict, "Conversation.StatusSubscribers", .two) + self._Conversation_StatusSubscribers_few = getValueWithForm(dict, "Conversation.StatusSubscribers", .few) + self._Conversation_StatusSubscribers_many = getValueWithForm(dict, "Conversation.StatusSubscribers", .many) + self._Conversation_StatusSubscribers_other = getValueWithForm(dict, "Conversation.StatusSubscribers", .other) self._SharedMedia_Link_zero = getValueWithForm(dict, "SharedMedia.Link", .zero) self._SharedMedia_Link_one = getValueWithForm(dict, "SharedMedia.Link", .one) self._SharedMedia_Link_two = getValueWithForm(dict, "SharedMedia.Link", .two) self._SharedMedia_Link_few = getValueWithForm(dict, "SharedMedia.Link", .few) self._SharedMedia_Link_many = getValueWithForm(dict, "SharedMedia.Link", .many) self._SharedMedia_Link_other = getValueWithForm(dict, "SharedMedia.Link", .other) - self._Map_ETAMinutes_zero = getValueWithForm(dict, "Map.ETAMinutes", .zero) - self._Map_ETAMinutes_one = getValueWithForm(dict, "Map.ETAMinutes", .one) - self._Map_ETAMinutes_two = getValueWithForm(dict, "Map.ETAMinutes", .two) - self._Map_ETAMinutes_few = getValueWithForm(dict, "Map.ETAMinutes", .few) - self._Map_ETAMinutes_many = getValueWithForm(dict, "Map.ETAMinutes", .many) - self._Map_ETAMinutes_other = getValueWithForm(dict, "Map.ETAMinutes", .other) + self._PrivacyLastSeenSettings_AddUsers_zero = getValueWithForm(dict, "PrivacyLastSeenSettings.AddUsers", .zero) + self._PrivacyLastSeenSettings_AddUsers_one = getValueWithForm(dict, "PrivacyLastSeenSettings.AddUsers", .one) + self._PrivacyLastSeenSettings_AddUsers_two = getValueWithForm(dict, "PrivacyLastSeenSettings.AddUsers", .two) + self._PrivacyLastSeenSettings_AddUsers_few = getValueWithForm(dict, "PrivacyLastSeenSettings.AddUsers", .few) + self._PrivacyLastSeenSettings_AddUsers_many = getValueWithForm(dict, "PrivacyLastSeenSettings.AddUsers", .many) + self._PrivacyLastSeenSettings_AddUsers_other = getValueWithForm(dict, "PrivacyLastSeenSettings.AddUsers", .other) + self._ForwardedVideoMessages_zero = getValueWithForm(dict, "ForwardedVideoMessages", .zero) + self._ForwardedVideoMessages_one = getValueWithForm(dict, "ForwardedVideoMessages", .one) + self._ForwardedVideoMessages_two = getValueWithForm(dict, "ForwardedVideoMessages", .two) + self._ForwardedVideoMessages_few = getValueWithForm(dict, "ForwardedVideoMessages", .few) + self._ForwardedVideoMessages_many = getValueWithForm(dict, "ForwardedVideoMessages", .many) + self._ForwardedVideoMessages_other = getValueWithForm(dict, "ForwardedVideoMessages", .other) + self._ForwardedMessages_zero = getValueWithForm(dict, "ForwardedMessages", .zero) + self._ForwardedMessages_one = getValueWithForm(dict, "ForwardedMessages", .one) + self._ForwardedMessages_two = getValueWithForm(dict, "ForwardedMessages", .two) + self._ForwardedMessages_few = getValueWithForm(dict, "ForwardedMessages", .few) + self._ForwardedMessages_many = getValueWithForm(dict, "ForwardedMessages", .many) + self._ForwardedMessages_other = getValueWithForm(dict, "ForwardedMessages", .other) + self._MessageTimer_Days_zero = getValueWithForm(dict, "MessageTimer.Days", .zero) + self._MessageTimer_Days_one = getValueWithForm(dict, "MessageTimer.Days", .one) + self._MessageTimer_Days_two = getValueWithForm(dict, "MessageTimer.Days", .two) + self._MessageTimer_Days_few = getValueWithForm(dict, "MessageTimer.Days", .few) + self._MessageTimer_Days_many = getValueWithForm(dict, "MessageTimer.Days", .many) + self._MessageTimer_Days_other = getValueWithForm(dict, "MessageTimer.Days", .other) + self._Call_ShortMinutes_zero = getValueWithForm(dict, "Call.ShortMinutes", .zero) + self._Call_ShortMinutes_one = getValueWithForm(dict, "Call.ShortMinutes", .one) + self._Call_ShortMinutes_two = getValueWithForm(dict, "Call.ShortMinutes", .two) + self._Call_ShortMinutes_few = getValueWithForm(dict, "Call.ShortMinutes", .few) + self._Call_ShortMinutes_many = getValueWithForm(dict, "Call.ShortMinutes", .many) + self._Call_ShortMinutes_other = getValueWithForm(dict, "Call.ShortMinutes", .other) + self._AttachmentMenu_SendVideo_zero = getValueWithForm(dict, "AttachmentMenu.SendVideo", .zero) + self._AttachmentMenu_SendVideo_one = getValueWithForm(dict, "AttachmentMenu.SendVideo", .one) + self._AttachmentMenu_SendVideo_two = getValueWithForm(dict, "AttachmentMenu.SendVideo", .two) + self._AttachmentMenu_SendVideo_few = getValueWithForm(dict, "AttachmentMenu.SendVideo", .few) + self._AttachmentMenu_SendVideo_many = getValueWithForm(dict, "AttachmentMenu.SendVideo", .many) + self._AttachmentMenu_SendVideo_other = getValueWithForm(dict, "AttachmentMenu.SendVideo", .other) self._MessageTimer_Minutes_zero = getValueWithForm(dict, "MessageTimer.Minutes", .zero) self._MessageTimer_Minutes_one = getValueWithForm(dict, "MessageTimer.Minutes", .one) self._MessageTimer_Minutes_two = getValueWithForm(dict, "MessageTimer.Minutes", .two) self._MessageTimer_Minutes_few = getValueWithForm(dict, "MessageTimer.Minutes", .few) self._MessageTimer_Minutes_many = getValueWithForm(dict, "MessageTimer.Minutes", .many) self._MessageTimer_Minutes_other = getValueWithForm(dict, "MessageTimer.Minutes", .other) - self._AttachmentMenu_SendPhoto_zero = getValueWithForm(dict, "AttachmentMenu.SendPhoto", .zero) - self._AttachmentMenu_SendPhoto_one = getValueWithForm(dict, "AttachmentMenu.SendPhoto", .one) - self._AttachmentMenu_SendPhoto_two = getValueWithForm(dict, "AttachmentMenu.SendPhoto", .two) - self._AttachmentMenu_SendPhoto_few = getValueWithForm(dict, "AttachmentMenu.SendPhoto", .few) - self._AttachmentMenu_SendPhoto_many = getValueWithForm(dict, "AttachmentMenu.SendPhoto", .many) - self._AttachmentMenu_SendPhoto_other = getValueWithForm(dict, "AttachmentMenu.SendPhoto", .other) - self._Notifications_ExceptionMuteExpires_Hours_zero = getValueWithForm(dict, "Notifications.ExceptionMuteExpires.Hours", .zero) - self._Notifications_ExceptionMuteExpires_Hours_one = getValueWithForm(dict, "Notifications.ExceptionMuteExpires.Hours", .one) - self._Notifications_ExceptionMuteExpires_Hours_two = getValueWithForm(dict, "Notifications.ExceptionMuteExpires.Hours", .two) - self._Notifications_ExceptionMuteExpires_Hours_few = getValueWithForm(dict, "Notifications.ExceptionMuteExpires.Hours", .few) - self._Notifications_ExceptionMuteExpires_Hours_many = getValueWithForm(dict, "Notifications.ExceptionMuteExpires.Hours", .many) - self._Notifications_ExceptionMuteExpires_Hours_other = getValueWithForm(dict, "Notifications.ExceptionMuteExpires.Hours", .other) + self._MessageTimer_Months_zero = getValueWithForm(dict, "MessageTimer.Months", .zero) + self._MessageTimer_Months_one = getValueWithForm(dict, "MessageTimer.Months", .one) + self._MessageTimer_Months_two = getValueWithForm(dict, "MessageTimer.Months", .two) + self._MessageTimer_Months_few = getValueWithForm(dict, "MessageTimer.Months", .few) + self._MessageTimer_Months_many = getValueWithForm(dict, "MessageTimer.Months", .many) + self._MessageTimer_Months_other = getValueWithForm(dict, "MessageTimer.Months", .other) + self._ServiceMessage_GameScoreSelfExtended_zero = getValueWithForm(dict, "ServiceMessage.GameScoreSelfExtended", .zero) + self._ServiceMessage_GameScoreSelfExtended_one = getValueWithForm(dict, "ServiceMessage.GameScoreSelfExtended", .one) + self._ServiceMessage_GameScoreSelfExtended_two = getValueWithForm(dict, "ServiceMessage.GameScoreSelfExtended", .two) + self._ServiceMessage_GameScoreSelfExtended_few = getValueWithForm(dict, "ServiceMessage.GameScoreSelfExtended", .few) + self._ServiceMessage_GameScoreSelfExtended_many = getValueWithForm(dict, "ServiceMessage.GameScoreSelfExtended", .many) + self._ServiceMessage_GameScoreSelfExtended_other = getValueWithForm(dict, "ServiceMessage.GameScoreSelfExtended", .other) + self._LiveLocation_MenuChatsCount_zero = getValueWithForm(dict, "LiveLocation.MenuChatsCount", .zero) + self._LiveLocation_MenuChatsCount_one = getValueWithForm(dict, "LiveLocation.MenuChatsCount", .one) + self._LiveLocation_MenuChatsCount_two = getValueWithForm(dict, "LiveLocation.MenuChatsCount", .two) + self._LiveLocation_MenuChatsCount_few = getValueWithForm(dict, "LiveLocation.MenuChatsCount", .few) + self._LiveLocation_MenuChatsCount_many = getValueWithForm(dict, "LiveLocation.MenuChatsCount", .many) + self._LiveLocation_MenuChatsCount_other = getValueWithForm(dict, "LiveLocation.MenuChatsCount", .other) + self._Call_Seconds_zero = getValueWithForm(dict, "Call.Seconds", .zero) + self._Call_Seconds_one = getValueWithForm(dict, "Call.Seconds", .one) + self._Call_Seconds_two = getValueWithForm(dict, "Call.Seconds", .two) + self._Call_Seconds_few = getValueWithForm(dict, "Call.Seconds", .few) + self._Call_Seconds_many = getValueWithForm(dict, "Call.Seconds", .many) + self._Call_Seconds_other = getValueWithForm(dict, "Call.Seconds", .other) + self._Call_Minutes_zero = getValueWithForm(dict, "Call.Minutes", .zero) + self._Call_Minutes_one = getValueWithForm(dict, "Call.Minutes", .one) + self._Call_Minutes_two = getValueWithForm(dict, "Call.Minutes", .two) + self._Call_Minutes_few = getValueWithForm(dict, "Call.Minutes", .few) + self._Call_Minutes_many = getValueWithForm(dict, "Call.Minutes", .many) + self._Call_Minutes_other = getValueWithForm(dict, "Call.Minutes", .other) + self._Conversation_StatusMembers_zero = getValueWithForm(dict, "Conversation.StatusMembers", .zero) + self._Conversation_StatusMembers_one = getValueWithForm(dict, "Conversation.StatusMembers", .one) + self._Conversation_StatusMembers_two = getValueWithForm(dict, "Conversation.StatusMembers", .two) + self._Conversation_StatusMembers_few = getValueWithForm(dict, "Conversation.StatusMembers", .few) + self._Conversation_StatusMembers_many = getValueWithForm(dict, "Conversation.StatusMembers", .many) + self._Conversation_StatusMembers_other = getValueWithForm(dict, "Conversation.StatusMembers", .other) + self._InviteText_ContactsCount_zero = getValueWithForm(dict, "InviteText.ContactsCount", .zero) + self._InviteText_ContactsCount_one = getValueWithForm(dict, "InviteText.ContactsCount", .one) + self._InviteText_ContactsCount_two = getValueWithForm(dict, "InviteText.ContactsCount", .two) + self._InviteText_ContactsCount_few = getValueWithForm(dict, "InviteText.ContactsCount", .few) + self._InviteText_ContactsCount_many = getValueWithForm(dict, "InviteText.ContactsCount", .many) + self._InviteText_ContactsCount_other = getValueWithForm(dict, "InviteText.ContactsCount", .other) + self._Contacts_ImportersCount_zero = getValueWithForm(dict, "Contacts.ImportersCount", .zero) + self._Contacts_ImportersCount_one = getValueWithForm(dict, "Contacts.ImportersCount", .one) + self._Contacts_ImportersCount_two = getValueWithForm(dict, "Contacts.ImportersCount", .two) + self._Contacts_ImportersCount_few = getValueWithForm(dict, "Contacts.ImportersCount", .few) + self._Contacts_ImportersCount_many = getValueWithForm(dict, "Contacts.ImportersCount", .many) + self._Contacts_ImportersCount_other = getValueWithForm(dict, "Contacts.ImportersCount", .other) self._Invitation_Members_zero = getValueWithForm(dict, "Invitation.Members", .zero) self._Invitation_Members_one = getValueWithForm(dict, "Invitation.Members", .one) self._Invitation_Members_two = getValueWithForm(dict, "Invitation.Members", .two) self._Invitation_Members_few = getValueWithForm(dict, "Invitation.Members", .few) self._Invitation_Members_many = getValueWithForm(dict, "Invitation.Members", .many) self._Invitation_Members_other = getValueWithForm(dict, "Invitation.Members", .other) + self._Conversation_StatusOnline_zero = getValueWithForm(dict, "Conversation.StatusOnline", .zero) + self._Conversation_StatusOnline_one = getValueWithForm(dict, "Conversation.StatusOnline", .one) + self._Conversation_StatusOnline_two = getValueWithForm(dict, "Conversation.StatusOnline", .two) + self._Conversation_StatusOnline_few = getValueWithForm(dict, "Conversation.StatusOnline", .few) + self._Conversation_StatusOnline_many = getValueWithForm(dict, "Conversation.StatusOnline", .many) + self._Conversation_StatusOnline_other = getValueWithForm(dict, "Conversation.StatusOnline", .other) + self._MessageTimer_Years_zero = getValueWithForm(dict, "MessageTimer.Years", .zero) + self._MessageTimer_Years_one = getValueWithForm(dict, "MessageTimer.Years", .one) + self._MessageTimer_Years_two = getValueWithForm(dict, "MessageTimer.Years", .two) + self._MessageTimer_Years_few = getValueWithForm(dict, "MessageTimer.Years", .few) + self._MessageTimer_Years_many = getValueWithForm(dict, "MessageTimer.Years", .many) + self._MessageTimer_Years_other = getValueWithForm(dict, "MessageTimer.Years", .other) + self._ForwardedStickers_zero = getValueWithForm(dict, "ForwardedStickers", .zero) + self._ForwardedStickers_one = getValueWithForm(dict, "ForwardedStickers", .one) + self._ForwardedStickers_two = getValueWithForm(dict, "ForwardedStickers", .two) + self._ForwardedStickers_few = getValueWithForm(dict, "ForwardedStickers", .few) + self._ForwardedStickers_many = getValueWithForm(dict, "ForwardedStickers", .many) + self._ForwardedStickers_other = getValueWithForm(dict, "ForwardedStickers", .other) + self._StickerPack_StickerCount_zero = getValueWithForm(dict, "StickerPack.StickerCount", .zero) + self._StickerPack_StickerCount_one = getValueWithForm(dict, "StickerPack.StickerCount", .one) + self._StickerPack_StickerCount_two = getValueWithForm(dict, "StickerPack.StickerCount", .two) + self._StickerPack_StickerCount_few = getValueWithForm(dict, "StickerPack.StickerCount", .few) + self._StickerPack_StickerCount_many = getValueWithForm(dict, "StickerPack.StickerCount", .many) + self._StickerPack_StickerCount_other = getValueWithForm(dict, "StickerPack.StickerCount", .other) + self._Watch_LastSeen_MinutesAgo_zero = getValueWithForm(dict, "Watch.LastSeen.MinutesAgo", .zero) + self._Watch_LastSeen_MinutesAgo_one = getValueWithForm(dict, "Watch.LastSeen.MinutesAgo", .one) + self._Watch_LastSeen_MinutesAgo_two = getValueWithForm(dict, "Watch.LastSeen.MinutesAgo", .two) + self._Watch_LastSeen_MinutesAgo_few = getValueWithForm(dict, "Watch.LastSeen.MinutesAgo", .few) + self._Watch_LastSeen_MinutesAgo_many = getValueWithForm(dict, "Watch.LastSeen.MinutesAgo", .many) + self._Watch_LastSeen_MinutesAgo_other = getValueWithForm(dict, "Watch.LastSeen.MinutesAgo", .other) + self._Notification_GameScoreSelfSimple_zero = getValueWithForm(dict, "Notification.GameScoreSelfSimple", .zero) + self._Notification_GameScoreSelfSimple_one = getValueWithForm(dict, "Notification.GameScoreSelfSimple", .one) + self._Notification_GameScoreSelfSimple_two = getValueWithForm(dict, "Notification.GameScoreSelfSimple", .two) + self._Notification_GameScoreSelfSimple_few = getValueWithForm(dict, "Notification.GameScoreSelfSimple", .few) + self._Notification_GameScoreSelfSimple_many = getValueWithForm(dict, "Notification.GameScoreSelfSimple", .many) + self._Notification_GameScoreSelfSimple_other = getValueWithForm(dict, "Notification.GameScoreSelfSimple", .other) + self._ServiceMessage_GameScoreSimple_zero = getValueWithForm(dict, "ServiceMessage.GameScoreSimple", .zero) + self._ServiceMessage_GameScoreSimple_one = getValueWithForm(dict, "ServiceMessage.GameScoreSimple", .one) + self._ServiceMessage_GameScoreSimple_two = getValueWithForm(dict, "ServiceMessage.GameScoreSimple", .two) + self._ServiceMessage_GameScoreSimple_few = getValueWithForm(dict, "ServiceMessage.GameScoreSimple", .few) + self._ServiceMessage_GameScoreSimple_many = getValueWithForm(dict, "ServiceMessage.GameScoreSimple", .many) + self._ServiceMessage_GameScoreSimple_other = getValueWithForm(dict, "ServiceMessage.GameScoreSimple", .other) + self._LastSeen_HoursAgo_zero = getValueWithForm(dict, "LastSeen.HoursAgo", .zero) + self._LastSeen_HoursAgo_one = getValueWithForm(dict, "LastSeen.HoursAgo", .one) + self._LastSeen_HoursAgo_two = getValueWithForm(dict, "LastSeen.HoursAgo", .two) + self._LastSeen_HoursAgo_few = getValueWithForm(dict, "LastSeen.HoursAgo", .few) + self._LastSeen_HoursAgo_many = getValueWithForm(dict, "LastSeen.HoursAgo", .many) + self._LastSeen_HoursAgo_other = getValueWithForm(dict, "LastSeen.HoursAgo", .other) + self._Map_ETAMinutes_zero = getValueWithForm(dict, "Map.ETAMinutes", .zero) + self._Map_ETAMinutes_one = getValueWithForm(dict, "Map.ETAMinutes", .one) + self._Map_ETAMinutes_two = getValueWithForm(dict, "Map.ETAMinutes", .two) + self._Map_ETAMinutes_few = getValueWithForm(dict, "Map.ETAMinutes", .few) + self._Map_ETAMinutes_many = getValueWithForm(dict, "Map.ETAMinutes", .many) + self._Map_ETAMinutes_other = getValueWithForm(dict, "Map.ETAMinutes", .other) + self._Notifications_ExceptionMuteExpires_Minutes_zero = getValueWithForm(dict, "Notifications.ExceptionMuteExpires.Minutes", .zero) + self._Notifications_ExceptionMuteExpires_Minutes_one = getValueWithForm(dict, "Notifications.ExceptionMuteExpires.Minutes", .one) + self._Notifications_ExceptionMuteExpires_Minutes_two = getValueWithForm(dict, "Notifications.ExceptionMuteExpires.Minutes", .two) + self._Notifications_ExceptionMuteExpires_Minutes_few = getValueWithForm(dict, "Notifications.ExceptionMuteExpires.Minutes", .few) + self._Notifications_ExceptionMuteExpires_Minutes_many = getValueWithForm(dict, "Notifications.ExceptionMuteExpires.Minutes", .many) + self._Notifications_ExceptionMuteExpires_Minutes_other = getValueWithForm(dict, "Notifications.ExceptionMuteExpires.Minutes", .other) + self._GroupInfo_ParticipantCount_zero = getValueWithForm(dict, "GroupInfo.ParticipantCount", .zero) + self._GroupInfo_ParticipantCount_one = getValueWithForm(dict, "GroupInfo.ParticipantCount", .one) + self._GroupInfo_ParticipantCount_two = getValueWithForm(dict, "GroupInfo.ParticipantCount", .two) + self._GroupInfo_ParticipantCount_few = getValueWithForm(dict, "GroupInfo.ParticipantCount", .few) + self._GroupInfo_ParticipantCount_many = getValueWithForm(dict, "GroupInfo.ParticipantCount", .many) + self._GroupInfo_ParticipantCount_other = getValueWithForm(dict, "GroupInfo.ParticipantCount", .other) + self._ForwardedVideos_zero = getValueWithForm(dict, "ForwardedVideos", .zero) + self._ForwardedVideos_one = getValueWithForm(dict, "ForwardedVideos", .one) + self._ForwardedVideos_two = getValueWithForm(dict, "ForwardedVideos", .two) + self._ForwardedVideos_few = getValueWithForm(dict, "ForwardedVideos", .few) + self._ForwardedVideos_many = getValueWithForm(dict, "ForwardedVideos", .many) + self._ForwardedVideos_other = getValueWithForm(dict, "ForwardedVideos", .other) + self._MessageTimer_ShortMinutes_zero = getValueWithForm(dict, "MessageTimer.ShortMinutes", .zero) + self._MessageTimer_ShortMinutes_one = getValueWithForm(dict, "MessageTimer.ShortMinutes", .one) + self._MessageTimer_ShortMinutes_two = getValueWithForm(dict, "MessageTimer.ShortMinutes", .two) + self._MessageTimer_ShortMinutes_few = getValueWithForm(dict, "MessageTimer.ShortMinutes", .few) + self._MessageTimer_ShortMinutes_many = getValueWithForm(dict, "MessageTimer.ShortMinutes", .many) + self._MessageTimer_ShortMinutes_other = getValueWithForm(dict, "MessageTimer.ShortMinutes", .other) + self._ForwardedAuthorsOthers_zero = getValueWithForm(dict, "ForwardedAuthorsOthers", .zero) + self._ForwardedAuthorsOthers_one = getValueWithForm(dict, "ForwardedAuthorsOthers", .one) + self._ForwardedAuthorsOthers_two = getValueWithForm(dict, "ForwardedAuthorsOthers", .two) + self._ForwardedAuthorsOthers_few = getValueWithForm(dict, "ForwardedAuthorsOthers", .few) + self._ForwardedAuthorsOthers_many = getValueWithForm(dict, "ForwardedAuthorsOthers", .many) + self._ForwardedAuthorsOthers_other = getValueWithForm(dict, "ForwardedAuthorsOthers", .other) + self._Call_ShortSeconds_zero = getValueWithForm(dict, "Call.ShortSeconds", .zero) + self._Call_ShortSeconds_one = getValueWithForm(dict, "Call.ShortSeconds", .one) + self._Call_ShortSeconds_two = getValueWithForm(dict, "Call.ShortSeconds", .two) + self._Call_ShortSeconds_few = getValueWithForm(dict, "Call.ShortSeconds", .few) + self._Call_ShortSeconds_many = getValueWithForm(dict, "Call.ShortSeconds", .many) + self._Call_ShortSeconds_other = getValueWithForm(dict, "Call.ShortSeconds", .other) + self._SharedMedia_Generic_zero = getValueWithForm(dict, "SharedMedia.Generic", .zero) + self._SharedMedia_Generic_one = getValueWithForm(dict, "SharedMedia.Generic", .one) + self._SharedMedia_Generic_two = getValueWithForm(dict, "SharedMedia.Generic", .two) + self._SharedMedia_Generic_few = getValueWithForm(dict, "SharedMedia.Generic", .few) + self._SharedMedia_Generic_many = getValueWithForm(dict, "SharedMedia.Generic", .many) + self._SharedMedia_Generic_other = getValueWithForm(dict, "SharedMedia.Generic", .other) + self._ForwardedAudios_zero = getValueWithForm(dict, "ForwardedAudios", .zero) + self._ForwardedAudios_one = getValueWithForm(dict, "ForwardedAudios", .one) + self._ForwardedAudios_two = getValueWithForm(dict, "ForwardedAudios", .two) + self._ForwardedAudios_few = getValueWithForm(dict, "ForwardedAudios", .few) + self._ForwardedAudios_many = getValueWithForm(dict, "ForwardedAudios", .many) + self._ForwardedAudios_other = getValueWithForm(dict, "ForwardedAudios", .other) + self._DialogList_LiveLocationChatsCount_zero = getValueWithForm(dict, "DialogList.LiveLocationChatsCount", .zero) + self._DialogList_LiveLocationChatsCount_one = getValueWithForm(dict, "DialogList.LiveLocationChatsCount", .one) + self._DialogList_LiveLocationChatsCount_two = getValueWithForm(dict, "DialogList.LiveLocationChatsCount", .two) + self._DialogList_LiveLocationChatsCount_few = getValueWithForm(dict, "DialogList.LiveLocationChatsCount", .few) + self._DialogList_LiveLocationChatsCount_many = getValueWithForm(dict, "DialogList.LiveLocationChatsCount", .many) + self._DialogList_LiveLocationChatsCount_other = getValueWithForm(dict, "DialogList.LiveLocationChatsCount", .other) + self._Watch_UserInfo_Mute_zero = getValueWithForm(dict, "Watch.UserInfo.Mute", .zero) + self._Watch_UserInfo_Mute_one = getValueWithForm(dict, "Watch.UserInfo.Mute", .one) + self._Watch_UserInfo_Mute_two = getValueWithForm(dict, "Watch.UserInfo.Mute", .two) + self._Watch_UserInfo_Mute_few = getValueWithForm(dict, "Watch.UserInfo.Mute", .few) + self._Watch_UserInfo_Mute_many = getValueWithForm(dict, "Watch.UserInfo.Mute", .many) + self._Watch_UserInfo_Mute_other = getValueWithForm(dict, "Watch.UserInfo.Mute", .other) + self._Conversation_LiveLocationMembersCount_zero = getValueWithForm(dict, "Conversation.LiveLocationMembersCount", .zero) + self._Conversation_LiveLocationMembersCount_one = getValueWithForm(dict, "Conversation.LiveLocationMembersCount", .one) + self._Conversation_LiveLocationMembersCount_two = getValueWithForm(dict, "Conversation.LiveLocationMembersCount", .two) + self._Conversation_LiveLocationMembersCount_few = getValueWithForm(dict, "Conversation.LiveLocationMembersCount", .few) + self._Conversation_LiveLocationMembersCount_many = getValueWithForm(dict, "Conversation.LiveLocationMembersCount", .many) + self._Conversation_LiveLocationMembersCount_other = getValueWithForm(dict, "Conversation.LiveLocationMembersCount", .other) + self._ForwardedFiles_zero = getValueWithForm(dict, "ForwardedFiles", .zero) + self._ForwardedFiles_one = getValueWithForm(dict, "ForwardedFiles", .one) + self._ForwardedFiles_two = getValueWithForm(dict, "ForwardedFiles", .two) + self._ForwardedFiles_few = getValueWithForm(dict, "ForwardedFiles", .few) + self._ForwardedFiles_many = getValueWithForm(dict, "ForwardedFiles", .many) + self._ForwardedFiles_other = getValueWithForm(dict, "ForwardedFiles", .other) } } diff --git a/TelegramUI/PresentationTheme.swift b/TelegramUI/PresentationTheme.swift index f949134d23..a4b6a352c4 100644 --- a/TelegramUI/PresentationTheme.swift +++ b/TelegramUI/PresentationTheme.swift @@ -259,11 +259,13 @@ public final class PresentationInputFieldTheme { public let backgroundColor: UIColor public let placeholderColor: UIColor public let primaryColor: UIColor + public let controlColor: UIColor - public init(backgroundColor: UIColor, placeholderColor: UIColor, primaryColor: UIColor) { + public init(backgroundColor: UIColor, placeholderColor: UIColor, primaryColor: UIColor, controlColor: UIColor) { self.backgroundColor = backgroundColor self.placeholderColor = placeholderColor self.primaryColor = primaryColor + self.controlColor = controlColor } } diff --git a/TelegramUI/ProxyListSettingsController.swift b/TelegramUI/ProxyListSettingsController.swift index 3f42cedcad..01f4a8d557 100644 --- a/TelegramUI/ProxyListSettingsController.swift +++ b/TelegramUI/ProxyListSettingsController.swift @@ -204,12 +204,12 @@ private enum ProxySettingsControllerEntry: ItemListNodeEntry { } } -private func proxySettingsControllerEntries(presentationData: PresentationData, state: ProxySettingsControllerState, proxySettings: ProxySettings, statuses: [ProxyServerSettings: ProxyServerStatus], connectionStatus: ConnectionStatus) -> [ProxySettingsControllerEntry] { +private func proxySettingsControllerEntries(theme: PresentationTheme, strings: PresentationStrings, state: ProxySettingsControllerState, proxySettings: ProxySettings, statuses: [ProxyServerSettings: ProxyServerStatus], connectionStatus: ConnectionStatus) -> [ProxySettingsControllerEntry] { var entries: [ProxySettingsControllerEntry] = [] - entries.append(.enabled(presentationData.theme, presentationData.strings.ChatSettings_ConnectionType_UseProxy, proxySettings.enabled, proxySettings.servers.isEmpty)) - entries.append(.serversHeader(presentationData.theme, presentationData.strings.SocksProxySetup_SavedProxies)) - entries.append(.addServer(presentationData.theme, presentationData.strings.SocksProxySetup_AddProxy, state.editing)) + entries.append(.enabled(theme, strings.ChatSettings_ConnectionType_UseProxy, proxySettings.enabled, proxySettings.servers.isEmpty)) + entries.append(.serversHeader(theme, strings.SocksProxySetup_SavedProxies)) + entries.append(.addServer(theme, strings.SocksProxySetup_AddProxy, state.editing)) var index = 0 for server in proxySettings.servers { let status: ProxyServerStatus = statuses[server] ?? .checking @@ -217,35 +217,35 @@ private func proxySettingsControllerEntries(presentationData: PresentationData, if proxySettings.enabled && server == proxySettings.activeServer { switch connectionStatus { case .waitingForNetwork: - displayStatus = DisplayProxyServerStatus(activity: true, text: presentationData.strings.State_WaitingForNetwork.lowercased(), textActive: false) + displayStatus = DisplayProxyServerStatus(activity: true, text: strings.State_WaitingForNetwork.lowercased(), textActive: false) case .connecting, .updating: - displayStatus = DisplayProxyServerStatus(activity: true, text: presentationData.strings.SocksProxySetup_ProxyStatusConnecting, textActive: false) + displayStatus = DisplayProxyServerStatus(activity: true, text: strings.SocksProxySetup_ProxyStatusConnecting, textActive: false) case .online: - var text = presentationData.strings.SocksProxySetup_ProxyStatusConnected + var text = strings.SocksProxySetup_ProxyStatusConnected if case let .available(rtt) = status { let pingTime: Int = Int(rtt * 1000.0) - text = text + ", \(presentationData.strings.SocksProxySetup_ProxyStatusPing("\(pingTime)").0)" + text = text + ", \(strings.SocksProxySetup_ProxyStatusPing("\(pingTime)").0)" } displayStatus = DisplayProxyServerStatus(activity: false, text: text, textActive: true) } } else { switch status { case .notAvailable: - displayStatus = DisplayProxyServerStatus(activity: false, text: presentationData.strings.SocksProxySetup_ProxyStatusUnavailable, textActive: false) + displayStatus = DisplayProxyServerStatus(activity: false, text: strings.SocksProxySetup_ProxyStatusUnavailable, textActive: false) case .checking: - displayStatus = DisplayProxyServerStatus(activity: false, text: presentationData.strings.SocksProxySetup_ProxyStatusChecking, textActive: false) + displayStatus = DisplayProxyServerStatus(activity: false, text: strings.SocksProxySetup_ProxyStatusChecking, textActive: false) case let .available(rtt): let pingTime: Int = Int(rtt * 1000.0) - displayStatus = DisplayProxyServerStatus(activity: false, text: presentationData.strings.SocksProxySetup_ProxyStatusPing("\(pingTime)").0, textActive: false) + displayStatus = DisplayProxyServerStatus(activity: false, text: strings.SocksProxySetup_ProxyStatusPing("\(pingTime)").0, textActive: false) } } - entries.append(.server(index, presentationData.theme, presentationData.strings, server, server == proxySettings.activeServer, displayStatus, ProxySettingsServerItemEditing(editable: true, editing: state.editing, revealed: state.revealedServer == server), proxySettings.enabled)) + entries.append(.server(index, theme, strings, server, server == proxySettings.activeServer, displayStatus, ProxySettingsServerItemEditing(editable: true, editing: state.editing, revealed: state.revealedServer == server), proxySettings.enabled)) index += 1 } if let activeServer = proxySettings.activeServer, case .socks5 = activeServer.connection { - entries.append(.useForCalls(presentationData.theme, presentationData.strings.SocksProxySetup_UseForCalls, proxySettings.useForCalls)) - entries.append(.useForCallsInfo(presentationData.theme, presentationData.strings.SocksProxySetup_UseForCallsHelp)) + entries.append(.useForCalls(theme, strings.SocksProxySetup_UseForCalls, proxySettings.useForCalls)) + entries.append(.useForCallsInfo(theme, strings.SocksProxySetup_UseForCallsHelp)) } return entries @@ -256,8 +256,19 @@ private struct ProxySettingsControllerState: Equatable { var revealedServer: ProxyServerSettings? = nil } -public func proxySettingsController(account: Account) -> ViewController { +public enum ProxySettingsControllerMode { + case `default` + case modal +} + +public func proxySettingsController(account: Account, mode: ProxySettingsControllerMode = .default) -> ViewController { + let presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 } + return proxySettingsController(postbox: account.postbox, network: account.network, mode: mode, theme: presentationData.theme, strings: presentationData.strings, updatedPresentationData: account.telegramApplicationContext.presentationData |> map { ($0.theme, $0.strings) }) +} + +public func proxySettingsController(postbox: Postbox, network: Network, mode: ProxySettingsControllerMode, theme: PresentationTheme, strings: PresentationStrings, updatedPresentationData: Signal<(theme: PresentationTheme, strings: PresentationStrings), NoError>) -> ViewController { var presentControllerImpl: ((ViewController, ViewControllerPresentationArguments?) -> Void)? + var dismissImpl: (() -> Void)? let stateValue = Atomic(value: ProxySettingsControllerState()) let statePromise = ValuePromise(stateValue.with { $0 }) let updateState: ((ProxySettingsControllerState) -> ProxySettingsControllerState) -> Void = { f in @@ -275,15 +286,15 @@ public func proxySettingsController(account: Account) -> ViewController { } let arguments = ProxySettingsControllerArguments(toggleEnabled: { value in - let _ = updateProxySettingsInteractively(postbox: account.postbox, network: account.network, { current in + let _ = updateProxySettingsInteractively(postbox: postbox, network: network, { current in var current = current current.enabled = value return current }).start() }, addNewServer: { - presentControllerImpl?(proxyServerSettingsController(account: account, currentSettings: nil), ViewControllerPresentationArguments(presentationAnimation: .modalSheet)) + presentControllerImpl?(proxyServerSettingsController(theme: theme, strings: strings, updatedPresentationData: updatedPresentationData, postbox: postbox, network: network, currentSettings: nil), ViewControllerPresentationArguments(presentationAnimation: .modalSheet)) }, activateServer: { server in - let _ = updateProxySettingsInteractively(postbox: account.postbox, network: account.network, { current in + let _ = updateProxySettingsInteractively(postbox: postbox, network: network, { current in var current = current if current.activeServer != server { if let _ = current.servers.index(of: server) { @@ -294,9 +305,9 @@ public func proxySettingsController(account: Account) -> ViewController { return current }).start() }, editServer: { server in - presentControllerImpl?(proxyServerSettingsController(account: account, currentSettings: server), ViewControllerPresentationArguments(presentationAnimation: .modalSheet)) + presentControllerImpl?(proxyServerSettingsController(theme: theme, strings: strings, updatedPresentationData: updatedPresentationData, postbox: postbox, network: network, currentSettings: server), ViewControllerPresentationArguments(presentationAnimation: .modalSheet)) }, removeServer: { server in - let _ = updateProxySettingsInteractively(postbox: account.postbox, network: account.network, { current in + let _ = updateProxySettingsInteractively(postbox: postbox, network: network, { current in var current = current if let index = current.servers.index(of: server) { current.servers.remove(at: index) @@ -316,7 +327,7 @@ public func proxySettingsController(account: Account) -> ViewController { return state } }, toggleUseForCalls: { value in - let _ = updateProxySettingsInteractively(postbox: account.postbox, network: account.network, { current in + let _ = updateProxySettingsInteractively(postbox: postbox, network: network, { current in var current = current current.useForCalls = value return current @@ -324,7 +335,7 @@ public func proxySettingsController(account: Account) -> ViewController { }) let proxySettings = Promise() - proxySettings.set(account.postbox.preferencesView(keys: [PreferencesKeys.proxySettings]) + proxySettings.set(postbox.preferencesView(keys: [PreferencesKeys.proxySettings]) |> map { preferencesView -> ProxySettings in if let value = preferencesView.values[PreferencesKeys.proxySettings] as? ProxySettings { return value @@ -333,44 +344,54 @@ public func proxySettingsController(account: Account) -> ViewController { } }) - let statusesContext = ProxyServersStatuses(network: account.network, servers: proxySettings.get() + let statusesContext = ProxyServersStatuses(network: network, servers: proxySettings.get() |> map { proxySettings -> [ProxyServerSettings] in return proxySettings.servers }) - let signal = combineLatest((account.applicationContext as! TelegramApplicationContext).presentationData, statePromise.get(), proxySettings.get(), statusesContext.statuses(), account.network.connectionStatus) - |> map { presentationData, state, proxySettings, statuses, connectionStatus -> (ItemListControllerState, (ItemListNodeState, ProxySettingsControllerEntry.ItemGenerationArguments)) in - let rightNavigationButton: ItemListNavigationButton? - if proxySettings.servers.isEmpty { - rightNavigationButton = nil - } else if state.editing { - rightNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Common_Done), style: .bold, enabled: true, action: { - updateState { state in - var state = state - state.editing = false - return state - } - }) - } else { - rightNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Common_Edit), style: .regular, enabled: true, action: { - updateState { state in - var state = state - state.editing = true - return state - } - }) - } - - let controllerState = ItemListControllerState(theme: presentationData.theme, title: .text(presentationData.strings.SocksProxySetup_Title), leftNavigationButton: nil, rightNavigationButton: rightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back)) - let listState = ItemListNodeState(entries: proxySettingsControllerEntries(presentationData: presentationData, state: state, proxySettings: proxySettings, statuses: statuses, connectionStatus: connectionStatus), style: .blocks) - - return (controllerState, (listState, arguments)) + let signal = combineLatest(updatedPresentationData, statePromise.get(), proxySettings.get(), statusesContext.statuses(), network.connectionStatus) + |> map { themeAndStrings, state, proxySettings, statuses, connectionStatus -> (ItemListControllerState, (ItemListNodeState, ProxySettingsControllerEntry.ItemGenerationArguments)) in + var leftNavigationButton: ItemListNavigationButton? + if case .modal = mode { + leftNavigationButton = ItemListNavigationButton(content: .text(themeAndStrings.strings.Common_Cancel), style: .regular, enabled: true, action: { + dismissImpl?() + }) + } + + let rightNavigationButton: ItemListNavigationButton? + if proxySettings.servers.isEmpty { + rightNavigationButton = nil + } else if state.editing { + rightNavigationButton = ItemListNavigationButton(content: .text(strings.Common_Done), style: .bold, enabled: true, action: { + updateState { state in + var state = state + state.editing = false + return state + } + }) + } else { + rightNavigationButton = ItemListNavigationButton(content: .text(strings.Common_Edit), style: .regular, enabled: true, action: { + updateState { state in + var state = state + state.editing = true + return state + } + }) + } + + let controllerState = ItemListControllerState(theme: themeAndStrings.0, title: .text(themeAndStrings.1.SocksProxySetup_Title), leftNavigationButton: leftNavigationButton, rightNavigationButton: rightNavigationButton, backNavigationButton: ItemListBackButton(title: themeAndStrings.1.Common_Back)) + let listState = ItemListNodeState(entries: proxySettingsControllerEntries(theme: themeAndStrings.0, strings: themeAndStrings.1, state: state, proxySettings: proxySettings, statuses: statuses, connectionStatus: connectionStatus), style: .blocks) + + return (controllerState, (listState, arguments)) } - let controller = ItemListController(account: account, state: signal) + let controller = ItemListController(theme: theme, strings: strings, updatedPresentationData: updatedPresentationData, state: signal, tabBarItem: nil) presentControllerImpl = { [weak controller] c, a in controller?.present(c, in: .window(.root), with: a) } + dismissImpl = { [weak controller] in + controller?.dismiss() + } controller.reorderEntry = { fromIndex, toIndex, entries in let fromEntry = entries[fromIndex] guard case let .server(_, _, _, fromServer, _, _, _, _) = fromEntry else { @@ -394,7 +415,7 @@ public func proxySettingsController(account: Account) -> ViewController { afterAll = true } - let _ = updateProxySettingsInteractively(postbox: account.postbox, network: account.network, { current in + let _ = updateProxySettingsInteractively(postbox: postbox, network: network, { current in var current = current if let index = current.servers.index(of: fromServer) { current.servers.remove(at: index) diff --git a/TelegramUI/ProxyServerSettingsController.swift b/TelegramUI/ProxyServerSettingsController.swift index a2c33a938f..d963c6641e 100644 --- a/TelegramUI/ProxyServerSettingsController.swift +++ b/TelegramUI/ProxyServerSettingsController.swift @@ -8,14 +8,17 @@ import MtProtoKitDynamic private final class proxyServerSettingsControllerArguments { let updateState: ((ProxyServerSettingsControllerState) -> ProxyServerSettingsControllerState) -> Void let share: () -> Void + let usePasteboardSettings: () -> Void - init(updateState: @escaping ((ProxyServerSettingsControllerState) -> ProxyServerSettingsControllerState) -> Void, share: @escaping () -> Void) { + init(updateState: @escaping ((ProxyServerSettingsControllerState) -> ProxyServerSettingsControllerState) -> Void, share: @escaping () -> Void, usePasteboardSettings: @escaping () -> Void) { self.updateState = updateState self.share = share + self.usePasteboardSettings = usePasteboardSettings } } private enum ProxySettingsSection: Int32 { + case pasteboard case mode case connection case credentials @@ -23,6 +26,9 @@ private enum ProxySettingsSection: Int32 { } private enum ProxySettingsEntry: ItemListNodeEntry { + case usePasteboardSettings(PresentationTheme, String) + case usePasteboardInfo(PresentationTheme, String) + case modeSocks5(PresentationTheme, String, Bool) case modeMtp(PresentationTheme, String, Bool) @@ -39,6 +45,8 @@ private enum ProxySettingsEntry: ItemListNodeEntry { var section: ItemListSectionId { switch self { + case .usePasteboardSettings, .usePasteboardInfo: + return ProxySettingsSection.pasteboard.rawValue case .modeSocks5, .modeMtp: return ProxySettingsSection.mode.rawValue case .connectionHeader, .connectionServer, .connectionPort: @@ -52,91 +60,30 @@ private enum ProxySettingsEntry: ItemListNodeEntry { var stableId: Int32 { switch self { - case .modeSocks5: + case .usePasteboardSettings: return 0 - case .modeMtp: + case .usePasteboardInfo: return 1 - case .connectionHeader: + case .modeSocks5: return 2 - case .connectionServer: + case .modeMtp: return 3 - case .connectionPort: + case .connectionHeader: return 4 - case .credentialsHeader: + case .connectionServer: return 5 - case .credentialsUsername: + case .connectionPort: return 6 - case .credentialsPassword: + case .credentialsHeader: return 7 - case .credentialsSecret: + case .credentialsUsername: return 8 - case .share: + case .credentialsPassword: return 9 - } - } - - static func ==(lhs: ProxySettingsEntry, rhs: ProxySettingsEntry) -> Bool { - switch lhs { - case let .modeSocks5(lhsTheme, lhsText, lhsValue): - if case let .modeSocks5(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue { - return true - } else { - return false - } - case let .modeMtp(lhsTheme, lhsText, lhsValue): - if case let .modeMtp(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue { - return true - } else { - return false - } - case let .connectionHeader(lhsTheme, lhsText): - if case let .connectionHeader(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText { - return true - } else { - return false - } - case let .connectionServer(lhsTheme, lhsText, lhsValue): - if case let .connectionServer(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue { - return true - } else { - return false - } - case let .connectionPort(lhsTheme, lhsText, lhsValue): - if case let .connectionPort(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue { - return true - } else { - return false - } - case let .credentialsHeader(lhsTheme, lhsText): - if case let .credentialsHeader(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText { - return true - } else { - return false - } - case let .credentialsUsername(lhsTheme, lhsText, lhsValue): - if case let .credentialsUsername(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue { - return true - } else { - return false - } - case let .credentialsPassword(lhsTheme, lhsText, lhsValue): - if case let .credentialsPassword(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue { - return true - } else { - return false - } - case let .credentialsSecret(lhsTheme, lhsText, lhsValue): - if case let .credentialsSecret(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue { - return true - } else { - return false - } - case let .share(lhsTheme, lhsText, lhsValue): - if case let .share(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue { - return true - } else { - return false - } + case .credentialsSecret: + return 10 + case .share: + return 11 } } @@ -146,6 +93,12 @@ private enum ProxySettingsEntry: ItemListNodeEntry { func item(_ arguments: proxyServerSettingsControllerArguments) -> ListViewItem { switch self { + case let .usePasteboardSettings(theme, title): + return ItemListActionItem(theme: theme, title: title, kind: .generic, alignment: .natural, sectionId: self.section, style: .blocks, action: { + arguments.usePasteboardSettings() + }) + case let .usePasteboardInfo(theme, text): + return ItemListTextItem(theme: theme, text: .plain(text), sectionId: self.section) case let .modeSocks5(theme, text, value): return ItemListCheckboxItem(theme: theme, title: text, style: .left, checked: value, zeroSeparatorInsets: false, sectionId: self.section, action: { arguments.updateState { state in @@ -250,9 +203,13 @@ private struct ProxyServerSettingsControllerState: Equatable { } } -private func proxyServerSettingsControllerEntries(presentationData: PresentationData, state: ProxyServerSettingsControllerState) -> [ProxySettingsEntry] { +private func proxyServerSettingsControllerEntries(presentationData: (theme: PresentationTheme, strings: PresentationStrings), state: ProxyServerSettingsControllerState, pasteboardSettings: ProxyServerSettings?) -> [ProxySettingsEntry] { var entries: [ProxySettingsEntry] = [] + if let _ = pasteboardSettings { + entries.append(.usePasteboardSettings(presentationData.theme, presentationData.strings.SocksProxySetup_PasteFromClipboard)) + } + entries.append(.modeSocks5(presentationData.theme, presentationData.strings.SocksProxySetup_ProxySocks5, state.mode == .socks5)) entries.append(.modeMtp(presentationData.theme, presentationData.strings.SocksProxySetup_ProxyTelegram, state.mode == .mtp)) @@ -275,11 +232,12 @@ private func proxyServerSettingsControllerEntries(presentationData: Presentation return entries } -func proxyServerSettingsController(account: Account, currentSettings: ProxyServerSettings?) -> ViewController { +func proxyServerSettingsController(theme: PresentationTheme, strings: PresentationStrings, updatedPresentationData: Signal<(theme: PresentationTheme, strings: PresentationStrings), NoError>, postbox: Postbox, network: Network, currentSettings: ProxyServerSettings?) -> ViewController { var currentMode: ProxyServerSettingsControllerMode = .socks5 var currentUsername: String? var currentPassword: String? var currentSecret: String? + var pasteboardSettings: ProxyServerSettings? if let currentSettings = currentSettings { switch currentSettings.connection { case let .socks5(username, password): @@ -290,7 +248,16 @@ func proxyServerSettingsController(account: Account, currentSettings: ProxyServe currentSecret = hexString(secret) currentMode = .mtp } + } else { + if let proxy = parseProxyUrl(UIPasteboard.general.string ?? "") { + if let secret = proxy.secret, secret.count == 16 || (secret.count == 17 && MTSocksProxySettings.secretSupportsExtendedPadding(secret)) { + pasteboardSettings = ProxyServerSettings(host: proxy.host, port: proxy.port, connection: .mtp(secret: secret)) + } else { + pasteboardSettings = ProxyServerSettings(host: proxy.host, port: proxy.port, connection: .socks5(username: proxy.username, password: proxy.password)) + } + } } + let initialState = ProxyServerSettingsControllerState(mode: currentMode, host: currentSettings?.host ?? "", port: (currentSettings?.port).flatMap { "\($0)" } ?? "", username: currentUsername ?? "", password: currentPassword ?? "", secret: currentSecret ?? "") let stateValue = Atomic(value: initialState) let statePromise = ValuePromise(initialState, ignoreRepeated: true) @@ -306,7 +273,7 @@ func proxyServerSettingsController(account: Account, currentSettings: ProxyServe }, share: { let state = stateValue.with { $0 } if state.isComplete { - let presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 } + let presentationData: (theme: PresentationTheme, strings: PresentationStrings) = (theme, strings) var result: String switch state.mode { case .mtp: @@ -323,62 +290,81 @@ func proxyServerSettingsController(account: Account, currentSettings: ProxyServe presentImpl?(standardTextAlertController(theme: AlertControllerTheme(presentationTheme: presentationData.theme), title: nil, text: presentationData.strings.Username_LinkCopied, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), nil) } + }, usePasteboardSettings: { + if let pasteboardSettings = pasteboardSettings { + updateState { state in + var state = state + state.host = pasteboardSettings.host + state.port = "\(pasteboardSettings.port)" + switch pasteboardSettings.connection { + case let .socks5(username, password): + state.mode = .socks5 + state.username = username ?? "" + state.password = password ?? "" + case let .mtp(secret): + state.mode = .mtp + state.secret = hexString(secret) + } + return state + } + } }) - let signal = combineLatest((account.applicationContext as! TelegramApplicationContext).presentationData, statePromise.get()) |> deliverOnMainQueue - |> map { presentationData, state -> (ItemListControllerState, (ItemListNodeState, ProxySettingsEntry.ItemGenerationArguments)) in - let leftNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Common_Cancel), style: .regular, enabled: true, action: { - dismissImpl?() - }) - let rightNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Common_Done), style: .bold, enabled: state.isComplete, action: { - var proxyServerSettings: ProxyServerSettings? - if state.isComplete, let port = Int32(state.port) { - switch state.mode { - case .socks5: - proxyServerSettings = ProxyServerSettings(host: state.host, port: port, connection: .socks5(username: state.username.isEmpty ? nil : state.username, password: state.password.isEmpty ? nil : state.password)) - case .mtp: - let data = dataWithHexString(state.secret) - var secretIsValid = false - if data.count == 16 { - secretIsValid = true - } else if data.count == 17 && MTSocksProxySettings.secretSupportsExtendedPadding(data) { - secretIsValid = true - } - if secretIsValid { - proxyServerSettings = ProxyServerSettings(host: state.host, port: port, connection: .mtp(secret: data)) - } - } + let signal = combineLatest(updatedPresentationData, statePromise.get()) + |> deliverOnMainQueue + |> map { presentationData, state -> (ItemListControllerState, (ItemListNodeState, ProxySettingsEntry.ItemGenerationArguments)) in + let leftNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Common_Cancel), style: .regular, enabled: true, action: { + dismissImpl?() + }) + let rightNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Common_Done), style: .bold, enabled: state.isComplete, action: { + var proxyServerSettings: ProxyServerSettings? + if state.isComplete, let port = Int32(state.port) { + switch state.mode { + case .socks5: + proxyServerSettings = ProxyServerSettings(host: state.host, port: port, connection: .socks5(username: state.username.isEmpty ? nil : state.username, password: state.password.isEmpty ? nil : state.password)) + case .mtp: + let data = dataWithHexString(state.secret) + var secretIsValid = false + if data.count == 16 { + secretIsValid = true + } else if data.count == 17 && MTSocksProxySettings.secretSupportsExtendedPadding(data) { + secretIsValid = true + } + if secretIsValid { + proxyServerSettings = ProxyServerSettings(host: state.host, port: port, connection: .mtp(secret: data)) + } } - if let proxyServerSettings = proxyServerSettings { - let _ = (updateProxySettingsInteractively(postbox: account.postbox, network: account.network, { settings in - var settings = settings - if let currentSettings = currentSettings { - if let index = settings.servers.index(of: currentSettings) { - settings.servers[index] = proxyServerSettings - if settings.activeServer == currentSettings { - settings.activeServer = proxyServerSettings - } - } - } else { - settings.servers.append(proxyServerSettings) - if settings.servers.count == 1 { + } + if let proxyServerSettings = proxyServerSettings { + let _ = (updateProxySettingsInteractively(postbox: postbox, network: network, { settings in + var settings = settings + if let currentSettings = currentSettings { + if let index = settings.servers.index(of: currentSettings) { + settings.servers[index] = proxyServerSettings + if settings.activeServer == currentSettings { settings.activeServer = proxyServerSettings } } - return settings - }) |> deliverOnMainQueue).start(completed: { - dismissImpl?() - }) - } - }) - - let controllerState = ItemListControllerState(theme: presentationData.theme, title: .text(presentationData.strings.SocksProxySetup_Title), leftNavigationButton: leftNavigationButton, rightNavigationButton: rightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: false) - let listState = ItemListNodeState(entries: proxyServerSettingsControllerEntries(presentationData: presentationData, state: state), style: .blocks, emptyStateItem: nil, animateChanges: false) - - return (controllerState, (listState, arguments)) + } else { + settings.servers.append(proxyServerSettings) + if settings.servers.count == 1 { + settings.activeServer = proxyServerSettings + } + } + return settings + }) |> deliverOnMainQueue).start(completed: { + dismissImpl?() + }) + } + }) + + let controllerState = ItemListControllerState(theme: presentationData.theme, title: .text(presentationData.strings.SocksProxySetup_Title), leftNavigationButton: leftNavigationButton, rightNavigationButton: rightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: false) + let listState = ItemListNodeState(entries: proxyServerSettingsControllerEntries(presentationData: presentationData, state: state, pasteboardSettings: pasteboardSettings), style: .blocks, emptyStateItem: nil, animateChanges: false) + + return (controllerState, (listState, arguments)) } - let controller = ItemListController(account: account, state: signal) + let controller = ItemListController(theme: theme, strings: strings, updatedPresentationData: updatedPresentationData, state: signal, tabBarItem: nil) presentImpl = { [weak controller] c, d in controller?.present(c, in: .window(.root), with: d) } diff --git a/TelegramUI/ResetPasswordController.swift b/TelegramUI/ResetPasswordController.swift new file mode 100644 index 0000000000..ddea0e806e --- /dev/null +++ b/TelegramUI/ResetPasswordController.swift @@ -0,0 +1,230 @@ +import Foundation +import Display +import SwiftSignalKit +import Postbox +import TelegramCore + +private final class ResetPasswordControllerArguments { + let updateCodeText: (String) -> Void + let openHelp: () -> Void + + init(updateCodeText: @escaping (String) -> Void, openHelp: @escaping () -> Void) { + self.updateCodeText = updateCodeText + self.openHelp = openHelp + } +} + +private enum ResetPasswordSection: Int32 { + case code + case help +} + +private enum ResetPasswordEntryTag: ItemListItemTag { + case code + + func isEqual(to other: ItemListItemTag) -> Bool { + if let other = other as? ResetPasswordEntryTag { + return self == other + } else { + return false + } + } +} + +private enum ResetPasswordEntry: ItemListNodeEntry, Equatable { + case code(PresentationTheme, String, String) + case codeInfo(PresentationTheme, String) + case helpInfo(PresentationTheme, String) + + var section: ItemListSectionId { + switch self { + case .code, .codeInfo: + return ResetPasswordSection.code.rawValue + case .helpInfo: + return ResetPasswordSection.help.rawValue + } + } + + var stableId: Int32 { + switch self { + case .code: + return 0 + case .codeInfo: + return 1 + case .helpInfo: + return 2 + } + } + + static func <(lhs: ResetPasswordEntry, rhs: ResetPasswordEntry) -> Bool { + return lhs.stableId < rhs.stableId + } + + func item(_ arguments: ResetPasswordControllerArguments) -> ListViewItem { + switch self { + case let .code(theme, text, value): + return ItemListSingleLineInputItem(theme: theme, title: NSAttributedString(string: text), text: value, placeholder: "", type: .number, spacing: 10.0, tag: ResetPasswordEntryTag.code, sectionId: self.section, textUpdated: { updatedText in + arguments.updateCodeText(updatedText) + }, action: { + }) + case let .codeInfo(theme, text): + return ItemListTextItem(theme: theme, text: .plain(text), sectionId: self.section) + case let .helpInfo(theme, text): + return ItemListTextItem(theme: theme, text: .markdown(text), sectionId: self.section, linkAction: { action in + if case .tap = action { + arguments.openHelp() + } + }) + } + } +} + +private struct ResetPasswordControllerState: Equatable { + var code: String = "" + var checking: Bool = false +} + +private func resetPasswordControllerEntries(presentationData: PresentationData, state: ResetPasswordControllerState, pattern: String) -> [ResetPasswordEntry] { + var entries: [ResetPasswordEntry] = [] + + entries.append(.code(presentationData.theme, presentationData.strings.TwoStepAuth_RecoveryCode, state.code)) + entries.append(.codeInfo(presentationData.theme, presentationData.strings.TwoStepAuth_RecoveryCodeHelp)) + + let stringData = presentationData.strings.TwoStepAuth_RecoveryEmailUnavailable(pattern) + var string = stringData.0 + if let (_, range) = stringData.1.first { + string.insert(contentsOf: "]()", at: string.index(string.startIndex, offsetBy: range.upperBound)) + string.insert(contentsOf: "[", at: string.index(string.startIndex, offsetBy: range.lowerBound)) + } + entries.append(.helpInfo(presentationData.theme, string)) + + return entries +} + +enum ResetPasswordState: Equatable { + case setup(currentPassword: String?) + case pendingVerification(emailPattern: String) +} + +func resetPasswordController(account: Account, emailPattern: String, completion: @escaping () -> Void) -> ViewController { + let statePromise = ValuePromise(ResetPasswordControllerState(), ignoreRepeated: true) + let stateValue = Atomic(value: ResetPasswordControllerState()) + let updateState: ((ResetPasswordControllerState) -> ResetPasswordControllerState) -> Void = { f in + statePromise.set(stateValue.modify { f($0) }) + } + + var dismissImpl: (() -> Void)? + var presentControllerImpl: ((ViewController, ViewControllerPresentationArguments?) -> Void)? + + let actionsDisposable = DisposableSet() + + let saveDisposable = MetaDisposable() + actionsDisposable.add(saveDisposable) + + let arguments = ResetPasswordControllerArguments(updateCodeText: { updatedText in + updateState { state in + var state = state + state.code = updatedText + return state + } + }, openHelp: { + let presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 } + presentControllerImpl?(standardTextAlertController(theme: AlertControllerTheme(presentationTheme: presentationData.theme), title: nil, text: presentationData.strings.TwoStepAuth_RecoveryFailed, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), nil) + }) + + var initialFocusImpl: (() -> Void)? + + let signal = combineLatest((account.applicationContext as! TelegramApplicationContext).presentationData, statePromise.get()) + |> deliverOnMainQueue + |> map { presentationData, state -> (ItemListControllerState, (ItemListNodeState, ResetPasswordEntry.ItemGenerationArguments)) in + + let leftNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Common_Cancel), style: .regular, enabled: true, action: { + dismissImpl?() + }) + var rightNavigationButton: ItemListNavigationButton? + if state.checking { + rightNavigationButton = ItemListNavigationButton(content: .none, style: .activity, enabled: true, action: {}) + } else { + rightNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Common_Done), style: .bold, enabled: !state.code.isEmpty, action: { + var state: ResetPasswordControllerState? + updateState { s in + state = s + return s + } + if let state = state, !state.checking, !state.code.isEmpty { + updateState { state in + var state = state + state.checking = true + return state + } + saveDisposable.set((recoverTwoStepVerificationPassword(network: account.network, code: state.code) + |> deliverOnMainQueue).start(error: { error in + updateState { state in + var state = state + state.checking = false + return state + } + let text: String + switch error { + case .invalidCode: + text = presentationData.strings.TwoStepAuth_RecoveryCodeInvalid + case .codeExpired: + text = presentationData.strings.TwoStepAuth_RecoveryCodeExpired + case .limitExceeded: + text = presentationData.strings.TwoStepAuth_FloodError + case .generic: + text = presentationData.strings.Login_UnknownError + } + let presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 } + presentControllerImpl?(standardTextAlertController(theme: AlertControllerTheme(presentationTheme: presentationData.theme), title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), nil) + }, completed: { + completion() + })) + } + }) + } + + let controllerState = ItemListControllerState(theme: presentationData.theme, title: .text(presentationData.strings.TwoStepAuth_RecoveryTitle), leftNavigationButton: leftNavigationButton, rightNavigationButton: rightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: false) + let listState = ItemListNodeState(entries: resetPasswordControllerEntries(presentationData: presentationData, state: state, pattern: emailPattern), style: .blocks, focusItemTag: ResetPasswordEntryTag.code, emptyStateItem: nil, animateChanges: false) + + return (controllerState, (listState, arguments)) + } + |> afterDisposed { + actionsDisposable.dispose() + } + + let controller = ItemListController(account: account, state: signal) + dismissImpl = { [weak controller] in + controller?.view.endEditing(true) + controller?.dismiss() + } + presentControllerImpl = { [weak controller] c, p in + if let controller = controller { + controller.present(c, in: .window(.root), with: p) + } + } + initialFocusImpl = { [weak controller] in + guard let controller = controller, controller.didAppearOnce else { + return + } + var resultItemNode: ItemListSingleLineInputItemNode? + let _ = controller.frameForItemNode({ itemNode in + if let itemNode = itemNode as? ItemListSingleLineInputItemNode, let tag = itemNode.tag, tag.isEqual(to: ResetPasswordEntryTag.code) { + resultItemNode = itemNode + return true + } + return false + }) + if let resultItemNode = resultItemNode { + resultItemNode.focus() + } + } + controller.didAppear = { firstTime in + if !firstTime { + return + } + initialFocusImpl?() + } + + return controller +} diff --git a/TelegramUI/SecureIdAuthController.swift b/TelegramUI/SecureIdAuthController.swift index 0821c1e645..4bf9b788de 100644 --- a/TelegramUI/SecureIdAuthController.swift +++ b/TelegramUI/SecureIdAuthController.swift @@ -9,16 +9,18 @@ final class SecureIdAuthControllerInteraction { let updateState: ((SecureIdAuthControllerState) -> SecureIdAuthControllerState) -> Void let present: (ViewController, Any?) -> Void let checkPassword: (String) -> Void + let openPasswordHelp: () -> Void let setupPassword: () -> Void let grant: () -> Void let openUrl: (String) -> Void let openMention: (TelegramPeerMention) -> Void let deleteAll: () -> Void - fileprivate init(updateState: @escaping ((SecureIdAuthControllerState) -> SecureIdAuthControllerState) -> Void, present: @escaping (ViewController, Any?) -> Void, checkPassword: @escaping (String) -> Void, setupPassword: @escaping () -> Void, grant: @escaping () -> Void, openUrl: @escaping (String) -> Void, openMention: @escaping (TelegramPeerMention) -> Void, deleteAll: @escaping () -> Void) { + fileprivate init(updateState: @escaping ((SecureIdAuthControllerState) -> SecureIdAuthControllerState) -> Void, present: @escaping (ViewController, Any?) -> Void, checkPassword: @escaping (String) -> Void, openPasswordHelp: @escaping () -> Void, setupPassword: @escaping () -> Void, grant: @escaping () -> Void, openUrl: @escaping (String) -> Void, openMention: @escaping (TelegramPeerMention) -> Void, deleteAll: @escaping () -> Void) { self.updateState = updateState self.present = present self.checkPassword = checkPassword + self.openPasswordHelp = openPasswordHelp self.setupPassword = setupPassword self.grant = grant self.openUrl = openUrl @@ -46,6 +48,7 @@ final class SecureIdAuthController: ViewController { private let challengeDisposable = MetaDisposable() private var formDisposable: Disposable? private let deleteDisposable = MetaDisposable() + private let recoveryDisposable = MetaDisposable() private var state: SecureIdAuthControllerState @@ -78,9 +81,9 @@ final class SecureIdAuthController: ViewController { strongSelf.updateState { state in var state = state if data.currentPasswordDerivation != nil { - state.verificationState = .passwordChallenge(data.currentHint ?? "", .none) + state.verificationState = .passwordChallenge(hint: data.currentHint ?? "", state: .none, hasRecoveryEmail: data.hasRecovery) } else { - state.verificationState = .noChallenge + state.verificationState = .noChallenge(data.unconfirmedEmailPattern) } return state } @@ -153,6 +156,7 @@ final class SecureIdAuthController: ViewController { self.challengeDisposable.dispose() self.formDisposable?.dispose() self.deleteDisposable.dispose() + self.recoveryDisposable.dispose() } override func viewDidAppear(_ animated: Bool) { @@ -178,6 +182,8 @@ final class SecureIdAuthController: ViewController { self?.present(c, in: .window(.root), with: a) }, checkPassword: { [weak self] password in self?.checkPassword(password: password, inBackground: false, completion: {}) + }, openPasswordHelp: { [weak self] in + self?.openPasswordHelp() }, setupPassword: { [weak self] in self?.setupPassword() }, grant: { [weak self] in @@ -240,17 +246,17 @@ final class SecureIdAuthController: ViewController { let state = f(self.state) if state != self.state { var previousHadProgress = false - if let verificationState = self.state.verificationState, case .passwordChallenge(_, .checking) = verificationState { + if let verificationState = self.state.verificationState, case .passwordChallenge(_, .checking, _) = verificationState { previousHadProgress = true } var updatedHasProgress = false - if let verificationState = state.verificationState, case .passwordChallenge(_, .checking) = verificationState { + if let verificationState = state.verificationState, case .passwordChallenge(_, .checking, _) = verificationState { updatedHasProgress = true } self.state = state if self.isNodeLoaded { - self.controllerNode.updateState(self.state, transition: .animated(duration: 0.3, curve: .spring)) + self.controllerNode.updateState(self.state, transition: animated ? .animated(duration: 0.3, curve: .spring) : .immediate) } if previousHadProgress != updatedHasProgress { @@ -269,7 +275,7 @@ final class SecureIdAuthController: ViewController { } @objc private func checkPassword(password: String, inBackground: Bool, completion: @escaping () -> Void) { - if let verificationState = self.state.verificationState, case let .passwordChallenge(hint, challengeState) = verificationState { + if let verificationState = self.state.verificationState, case let .passwordChallenge(hint, challengeState, hasRecoveryEmail) = verificationState { switch challengeState { case .none, .invalid: break @@ -278,12 +284,12 @@ final class SecureIdAuthController: ViewController { } self.updateState(animated: !inBackground, { state in var state = state - state.verificationState = .passwordChallenge(hint, .checking) + state.verificationState = .passwordChallenge(hint: hint, state: .checking, hasRecoveryEmail: hasRecoveryEmail) return state }) self.challengeDisposable.set((accessSecureId(network: self.account.network, password: password) |> deliverOnMainQueue).start(next: { [weak self] context in - guard let strongSelf = self, let verificationState = strongSelf.state.verificationState, case .passwordChallenge(_, .checking) = verificationState else { + guard let strongSelf = self, let verificationState = strongSelf.state.verificationState, case .passwordChallenge(_, .checking, _) = verificationState else { return } strongSelf.updateState(animated: !inBackground, { state in @@ -322,10 +328,10 @@ final class SecureIdAuthController: ViewController { } strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationTheme: strongSelf.presentationData.theme), title: nil, text: errorText, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), in: .window(.root)) - if let verificationState = strongSelf.state.verificationState, case let .passwordChallenge(hint, .checking) = verificationState { + if let verificationState = strongSelf.state.verificationState, case let .passwordChallenge(hint, .checking, hasRecoveryEmail) = verificationState { strongSelf.updateState(animated: !inBackground, { state in var state = state - state.verificationState = .passwordChallenge(hint, .invalid) + state.verificationState = .passwordChallenge(hint: hint, state: .invalid, hasRecoveryEmail: hasRecoveryEmail) return state }) } @@ -334,26 +340,87 @@ final class SecureIdAuthController: ViewController { } } - @objc private func setupPassword() { - var completionImpl: ((String, String) -> Void)? - let controller = createPasswordController(account: self.account, completion: { password, hint in - completionImpl?(password, hint) + private func openPasswordHelp() { + guard let verificationState = self.state.verificationState, case let .passwordChallenge(passwordChallenge) = verificationState, case .none = passwordChallenge.state else { + return + } + + if passwordChallenge.hasRecoveryEmail { + self.present(standardTextAlertController(theme: AlertControllerTheme(presentationTheme: self.presentationData.theme), title: self.presentationData.strings.Passport_ForgottenPassword, text: self.presentationData.strings.Passport_PasswordReset, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .defaultAction, title: presentationData.strings.Login_ResetAccountProtected_Reset, action: { [weak self] in + guard let strongSelf = self else { + return + } + strongSelf.recoveryDisposable.set((requestTwoStepVerificationPasswordRecoveryCode(network: strongSelf.account.network) + |> deliverOnMainQueue).start(next: { emailPattern in + guard let strongSelf = self else { + return + } + var completionImpl: (() -> Void)? + let controller = resetPasswordController(account: strongSelf.account, emailPattern: emailPattern, completion: { + completionImpl?() + }) + completionImpl = { [weak controller] in + guard let strongSelf = self else { + return + } + strongSelf.updateState(animated: false, { state in + var state = state + state.verificationState = .noChallenge(nil) + return state + }) + controller?.view.endEditing(true) + controller?.dismiss() + strongSelf.setupPassword() + } + strongSelf.present(controller, in: .window(.root), with: ViewControllerPresentationArguments(presentationAnimation: .modalSheet)) + })) + })]), in: .window(.root)) + } else { + self.present(standardTextAlertController(theme: AlertControllerTheme(presentationTheme: self.presentationData.theme), title: nil, text: self.presentationData.strings.TwoStepAuth_RecoveryUnavailable, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root)) + } + } + + private func setupPassword() { + guard let verificationState = self.state.verificationState, case let .noChallenge(emailPattern) = verificationState else { + return + } + var completionImpl: ((String, String, Bool) -> Void)? + let state: CreatePasswordState + if let emailPattern = emailPattern { + state = .pendingVerification(emailPattern: emailPattern) + } else { + state = .setup(currentPassword: nil) + } + let controller = createPasswordController(account: self.account, state: state, completion: { password, hint, hasRecoveryEmail in + completionImpl?(password, hint, hasRecoveryEmail) + }, updatePasswordEmailConfirmation: { [weak self] pattern in + guard let strongSelf = self else { + return + } + strongSelf.updateState(animated: false, { state in + var state = state + if let verificationState = state.verificationState, case .noChallenge = verificationState { + state.verificationState = .noChallenge(pattern) + } + return state + }) }) - completionImpl = { [weak self, weak controller] password, hint in + completionImpl = { [weak self, weak controller] password, hint, hasRecoveryEmail in guard let strongSelf = self else { controller?.dismiss() return } strongSelf.updateState(animated: false, { state in var state = state - state.verificationState = .passwordChallenge(hint, .none) + state.verificationState = .passwordChallenge(hint: hint, state: .none, hasRecoveryEmail: hasRecoveryEmail) return state }) strongSelf.checkPassword(password: password, inBackground: true, completion: { + controller?.view.endEditing(true) controller?.dismiss() }) } - self.present(controller, in: .window(.root)) + self.present(controller, in: .window(.root), with: ViewControllerPresentationArguments(presentationAnimation: .modalSheet)) } @objc private func grantAccess() { diff --git a/TelegramUI/SecureIdAuthControllerNode.swift b/TelegramUI/SecureIdAuthControllerNode.swift index acb57b3d97..b6e4eb862d 100644 --- a/TelegramUI/SecureIdAuthControllerNode.swift +++ b/TelegramUI/SecureIdAuthControllerNode.swift @@ -58,7 +58,12 @@ final class SecureIdAuthControllerNode: ViewControllerTracingNode { func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) { self.validLayout = (layout, navigationBarHeight) - var insets = layout.insets(options: [.input]) + var insetOptions: ContainerViewLayoutInsetOptions = [] + if self.contentNode is SecureIdAuthPasswordOptionContentNode { + insetOptions.insert(.input) + } + + var insets = layout.insets(options: insetOptions) insets.bottom = max(insets.bottom, layout.safeInsets.bottom) let headerNodeTransition: ContainedViewLayoutTransition = headerNode.bounds.isEmpty ? .immediate : transition @@ -152,7 +157,11 @@ final class SecureIdAuthControllerNode: ViewControllerTracingNode { if let contentNode = self.contentNode { self.scrollNode.addSubnode(contentNode) if let _ = self.validLayout { - self.scheduleLayoutTransitionRequest(.animated(duration: 0.5, curve: .spring)) + if transition.isAnimated { + self.scheduleLayoutTransitionRequest(.animated(duration: 0.5, curve: .spring)) + } else { + self.scheduleLayoutTransitionRequest(.immediate) + } } } } @@ -180,7 +189,7 @@ final class SecureIdAuthControllerNode: ViewControllerTracingNode { }) contentNode = current } - case let .passwordChallenge(hint, challengeState): + case let .passwordChallenge(hint, challengeState, _): if let current = self.contentNode as? SecureIdAuthPasswordOptionContentNode { current.updateIsChecking(challengeState == .checking) contentNode = current @@ -190,9 +199,7 @@ final class SecureIdAuthControllerNode: ViewControllerTracingNode { strongSelf.interaction.checkPassword(password) } }, passwordHelp: { [weak self] in - if let strongSelf = self { - - } + self?.interaction.openPasswordHelp() }) current.updateIsChecking(challengeState == .checking) contentNode = current @@ -227,7 +234,9 @@ final class SecureIdAuthControllerNode: ViewControllerTracingNode { if case .verified = verificationState { if self.acceptNode.supernode == nil { self.addSubnode(self.acceptNode) - self.acceptNode.layer.animatePosition(from: CGPoint(x: 0.0, y: self.acceptNode.bounds.height), to: CGPoint(), duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring, additive: true) + if transition.isAnimated { + self.acceptNode.layer.animatePosition(from: CGPoint(x: 0.0, y: self.acceptNode.bounds.height), to: CGPoint(), duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring, additive: true) + } } } @@ -253,7 +262,7 @@ final class SecureIdAuthControllerNode: ViewControllerTracingNode { var contentNode: (ASDisplayNode & SecureIdAuthContentNode)? switch verificationState { - case let .passwordChallenge(hint, challengeState): + case let .passwordChallenge(hint, challengeState, _): if let current = self.contentNode as? SecureIdAuthPasswordOptionContentNode { current.updateIsChecking(challengeState == .checking) contentNode = current diff --git a/TelegramUI/SecureIdAuthControllerState.swift b/TelegramUI/SecureIdAuthControllerState.swift index 613b18c350..a7a22438ee 100644 --- a/TelegramUI/SecureIdAuthControllerState.swift +++ b/TelegramUI/SecureIdAuthControllerState.swift @@ -16,32 +16,9 @@ enum SecureIdAuthPasswordChallengeState { } enum SecureIdAuthControllerVerificationState: Equatable { - case noChallenge - case passwordChallenge(String, SecureIdAuthPasswordChallengeState) + case noChallenge(String?) + case passwordChallenge(hint: String, state: SecureIdAuthPasswordChallengeState, hasRecoveryEmail: Bool) case verified(SecureIdAccessContext) - - static func ==(lhs: SecureIdAuthControllerVerificationState, rhs: SecureIdAuthControllerVerificationState) -> Bool { - switch lhs { - case .noChallenge: - if case .noChallenge = rhs { - return true - } else { - return false - } - case let .passwordChallenge(hint, state): - if case .passwordChallenge(hint, state) = rhs { - return true - } else { - return false - } - case .verified: - if case .verified = rhs { - return true - } else { - return false - } - } - } } struct SecureIdAuthControllerFormState: Equatable { diff --git a/TelegramUI/SecureIdAuthFormFieldNode.swift b/TelegramUI/SecureIdAuthFormFieldNode.swift index 20254ebee0..4bdf11c25a 100644 --- a/TelegramUI/SecureIdAuthFormFieldNode.swift +++ b/TelegramUI/SecureIdAuthFormFieldNode.swift @@ -154,8 +154,15 @@ func parseRequestedFormFields(_ types: [SecureIdRequestedFormField]) -> [SecureI if values.identity.documents.isEmpty { result.append(.identity(personalDetails: ParsedRequestedPersonalDetails(nativeNames: values.identity.nativeNames), document: nil, selfie: false, translation: false)) } else { - for document in values.identity.documents { - result.append(.identity(personalDetails: values.identity.details ? ParsedRequestedPersonalDetails(nativeNames: values.identity.nativeNames) : nil, document: document, selfie: values.identity.selfie, translation: values.identity.translation)) + if values.identity.details && values.identity.documents.count == 1 { + result.append(.identity(personalDetails: values.identity.details ? ParsedRequestedPersonalDetails(nativeNames: values.identity.nativeNames) : nil, document: values.identity.documents.first, selfie: values.identity.selfie, translation: values.identity.translation)) + } else { + if values.identity.details { + result.append(.identity(personalDetails: ParsedRequestedPersonalDetails(nativeNames: values.identity.nativeNames), document: nil, selfie: values.identity.selfie, translation: false)) + } + for document in values.identity.documents { + result.append(.identity(personalDetails: nil, document: document, selfie: values.identity.selfie, translation: values.identity.translation)) + } } } } @@ -163,8 +170,15 @@ func parseRequestedFormFields(_ types: [SecureIdRequestedFormField]) -> [SecureI if values.address.documents.isEmpty { result.append(.address(addressDetails: true, document: nil, translation: false)) } else { - for document in values.address.documents { - result.append(.address(addressDetails: values.address.details, document: document, translation: values.address.translation)) + if values.address.details && values.address.documents.count == 1 { + result.append(.address(addressDetails: true, document: values.address.documents.first, translation: false)) + } else { + if values.address.details { + result.append(.address(addressDetails: true, document: nil, translation: false)) + } + for document in values.address.documents { + result.append(.address(addressDetails: false, document: document, translation: values.address.translation)) + } } } } @@ -259,6 +273,19 @@ private func stringForDocumentType(_ type: SecureIdRequestedIdentityDocument, st } } +private func placeholderForDocumentType(_ type: SecureIdRequestedIdentityDocument, strings: PresentationStrings) -> String { + switch type { + case .passport: + return strings.Passport_Identity_TypePassportUploadScan + case .internalPassport: + return strings.Passport_Identity_TypeInternalPassportUploadScan + case .idCard: + return strings.Passport_Identity_TypeIdentityCardUploadScan + case .driversLicense: + return strings.Passport_Identity_TypeDriversLicenseUploadScan + } +} + private func stringForDocumentType(_ type: SecureIdRequestedAddressDocument, strings: PresentationStrings) -> String { switch type { case .rentalAgreement: @@ -274,23 +301,103 @@ private func stringForDocumentType(_ type: SecureIdRequestedAddressDocument, str } } +private func placeholderForDocumentType(_ type: SecureIdRequestedAddressDocument, strings: PresentationStrings) -> String { + switch type { + case .rentalAgreement: + return strings.Passport_Address_TypeRentalAgreementUploadScan + case .bankStatement: + return strings.Passport_Address_TypeBankStatementUploadScan + case .passportRegistration: + return strings.Passport_Address_TypePassportRegistrationUploadScan + case .temporaryRegistration: + return strings.Passport_Address_TypeTemporaryRegistrationUploadScan + case .utilityBill: + return strings.Passport_Address_TypeUtilityBillUploadScan + } +} + +private func placeholderForDocumentTypes(_ types: [SecureIdRequestedIdentityDocument], strings: PresentationStrings) -> String { + func stringForDocumentType(_ type: SecureIdRequestedIdentityDocument, strings: PresentationStrings) -> String { + switch type { + case .passport: + return strings.Passport_Identity_OneOfTypePassport + case .internalPassport: + return strings.Passport_Identity_OneOfTypeInternalPassport + case .idCard: + return strings.Passport_Identity_OneOfTypeIdentityCard + case .driversLicense: + return strings.Passport_Identity_OneOfTypeDriversLicense + } + } + + var string = "" + for i in 0 ..< types.count { + let type = types[i] + string.append(stringForDocumentType(type, strings: strings)) + if i < types.count - 2 { + string.append(strings.Passport_FieldOneOf_Delimeter) + } else if i < types.count - 1 { + string.append(strings.Passport_FieldOneOf_FinalDelimeter) + } + } + + return strings.Passport_Identity_UploadOneOfScan(string).0 +} + +private func placeholderForDocumentTypes(_ types: [SecureIdRequestedAddressDocument], strings: PresentationStrings) -> String { + func stringForDocumentType(_ type: SecureIdRequestedAddressDocument, strings: PresentationStrings) -> String { + switch type { + case .rentalAgreement: + return strings.Passport_Address_OneOfTypeRentalAgreement + case .bankStatement: + return strings.Passport_Address_OneOfTypeBankStatement + case .passportRegistration: + return strings.Passport_Address_OneOfTypePassportRegistration + case .temporaryRegistration: + return strings.Passport_Address_OneOfTypeTemporaryRegistration + case .utilityBill: + return strings.Passport_Address_OneOfTypeUtilityBill + } + } + + var string = "" + for i in 0 ..< types.count { + let type = types[i] + string.append(stringForDocumentType(type, strings: strings)) + if i < types.count - 2 { + string.append(strings.Passport_FieldOneOf_Delimeter) + } else if i < types.count - 1 { + string.append(strings.Passport_FieldOneOf_FinalDelimeter) + } + } + + return strings.Passport_Address_UploadOneOfScan(string).0 +} + private func fieldTitleAndText(field: SecureIdParsedRequestedFormField, strings: PresentationStrings, values: [SecureIdValueWithContext]) -> (String, String) { var title: String - let placeholder: String + var placeholder: String var text: String = "" switch field { case let .identity(personalDetails, document, _, _): if let document = document { title = strings.Passport_FieldIdentity + placeholder = strings.Passport_FieldIdentityUploadHelp + switch document { case let .just(type): title = stringForDocumentType(type, strings: strings) + placeholder = placeholderForDocumentType(type, strings: strings) break case let .oneOf(types): + let typesArray = Array(types) + if typesArray.count == 2 { + title = strings.Passport_FieldOneOf_Or(stringForDocumentType(typesArray[0], strings: strings), stringForDocumentType(typesArray[1], strings: strings)).0 + } + placeholder = placeholderForDocumentTypes(typesArray, strings: strings) break } - placeholder = strings.Passport_FieldIdentityUploadHelp } else { title = strings.Passport_Identity_TypePersonalDetails placeholder = strings.Passport_FieldIdentityDetailsHelp @@ -307,14 +414,20 @@ private func fieldTitleAndText(field: SecureIdParsedRequestedFormField, strings: case let .address(addressDetails, document, _): if let document = document { title = strings.Passport_FieldAddress + placeholder = strings.Passport_FieldAddressUploadHelp switch document { case let .just(type): title = stringForDocumentType(type, strings: strings) + placeholder = placeholderForDocumentType(type, strings: strings) break case let .oneOf(types): + let typesArray = Array(types) + if typesArray.count == 2 { + title = strings.Passport_FieldOneOf_Or(stringForDocumentType(typesArray[0], strings: strings), stringForDocumentType(typesArray[1], strings: strings)).0 + } + placeholder = placeholderForDocumentTypes(typesArray, strings: strings) break } - placeholder = strings.Passport_FieldAddressUploadHelp } else { title = strings.Passport_FieldAddress placeholder = strings.Passport_FieldAddressHelp diff --git a/TelegramUI/SecureIdAuthPasswordOptionContentNode.swift b/TelegramUI/SecureIdAuthPasswordOptionContentNode.swift index d0af8f4e56..1a2c994768 100644 --- a/TelegramUI/SecureIdAuthPasswordOptionContentNode.swift +++ b/TelegramUI/SecureIdAuthPasswordOptionContentNode.swift @@ -13,6 +13,7 @@ final class SecureIdAuthPasswordOptionContentNode: ASDisplayNode, SecureIdAuthCo private let titleNode: ImmediateTextNode private let inputBackground: ASImageNode private let inputField: TextFieldNode + private let inputButtonNode: HighlightableButtonNode private let buttonNode: HighlightableButtonNode private let buttonBackground: ASImageNode @@ -39,6 +40,13 @@ final class SecureIdAuthPasswordOptionContentNode: ASDisplayNode, SecureIdAuthCo self.titleNode.textAlignment = .center self.inputField = TextFieldNode() + self.inputButtonNode = HighlightableButtonNode() + + if let image = generateTintedImage(image: UIImage(bundleImageName: "Secure ID/PasswordHelpIcon"), color: theme.list.freeInputField.controlColor) { + self.inputButtonNode.setImage(image, for: []) + self.inputButtonNode.frame = CGRect(origin: CGPoint(), size: image.size) + } + self.inputBackground.image = generateStretchableFilledCircleImage(radius: 10.0, color: theme.list.freeInputField.backgroundColor) self.inputField.textField.isSecureTextEntry = true @@ -65,6 +73,7 @@ final class SecureIdAuthPasswordOptionContentNode: ASDisplayNode, SecureIdAuthCo self.inputContainer.addSubnode(self.titleNode) self.inputContainer.addSubnode(self.inputBackground) self.inputContainer.addSubnode(self.inputField) + self.inputContainer.addSubnode(self.inputButtonNode) self.inputContainer.addSubnode(self.buttonNode) self.addSubnode(self.inputContainer) @@ -84,6 +93,9 @@ final class SecureIdAuthPasswordOptionContentNode: ASDisplayNode, SecureIdAuthCo self.buttonNode.addTarget(self, action: #selector(self.buttonPressed), forControlEvents: .touchUpInside) self.inputField.textField.delegate = self + + self.inputButtonNode.hitTestSlop = UIEdgeInsets(top: -4.0, left: -4.0, bottom: -4.0, right: -4.0) + self.inputButtonNode.addTarget(self, action: #selector(self.inputButtonPressed), forControlEvents: .touchUpInside) } func updateLayout(width: CGFloat, transition: ContainedViewLayoutTransition) -> SecureIdAuthContentLayout { @@ -110,7 +122,11 @@ final class SecureIdAuthPasswordOptionContentNode: ASDisplayNode, SecureIdAuthCo transition.updateFrame(node: self.inputContainer, frame: inputContainerFrame) transition.updateFrame(node: self.titleNode, frame: titleFrame) transition.updateFrame(node: self.inputBackground, frame: inputFrame) - transition.updateFrame(node: self.inputField, frame: inputFrame.insetBy(dx: 6.0, dy: 0.0)) + var inputFieldFrame = inputFrame.insetBy(dx: 6.0, dy: 0.0) + inputFieldFrame.size.width -= 16.0 + transition.updateFrame(node: self.inputField, frame: inputFieldFrame) + + transition.updateFrame(node: self.inputButtonNode, frame: CGRect(origin: CGPoint(x: inputFrame.maxX - self.inputButtonNode.bounds.size.width - 6.0, y: inputFrame.minY + floor((inputFrame.height - self.inputButtonNode.bounds.size.height) / 2.0)), size: self.inputButtonNode.bounds.size)) let buttonBounds = CGRect(origin: CGPoint(), size: buttonSize) transition.updateFrame(node: self.buttonNode, frame: buttonBounds.offsetBy(dx: floor((width - buttonSize.width) / 2.0), dy: inputFrame.maxY + buttonSpacing)) @@ -152,6 +168,10 @@ final class SecureIdAuthPasswordOptionContentNode: ASDisplayNode, SecureIdAuthCo } } + @objc private func inputButtonPressed() { + self.passwordHelp() + } + func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { return !self.isChecking } diff --git a/TelegramUI/SelectivePrivacySettingsController.swift b/TelegramUI/SelectivePrivacySettingsController.swift index f50547ac38..5d385fbc32 100644 --- a/TelegramUI/SelectivePrivacySettingsController.swift +++ b/TelegramUI/SelectivePrivacySettingsController.swift @@ -502,10 +502,20 @@ func selectivePrivacySettingsController(account: Account, kind: SelectivePrivacy updateState { state in return state.withUpdatedCallsP2PMode(mode) } + let _ = updateVoiceCallSettingsSettingsInteractively(postbox: account.postbox, { settings in + var settings = settings + settings.p2pMode = mode + return settings + }).start() }, updateCallsIntegrationEnabled: { enabled in updateState { state in return state.withUpdatedCallsIntegrationEnabled(enabled) } + let _ = updateVoiceCallSettingsSettingsInteractively(postbox: account.postbox, { settings in + var settings = settings + settings.enableSystemIntegration = enabled + return settings + }).start() }) let signal = combineLatest((account.applicationContext as! TelegramApplicationContext).presentationData, statePromise.get()) |> deliverOnMainQueue diff --git a/TelegramUI/SettingsController.swift b/TelegramUI/SettingsController.swift index dd99b17d5f..3e7d5a35b9 100644 --- a/TelegramUI/SettingsController.swift +++ b/TelegramUI/SettingsController.swift @@ -345,7 +345,7 @@ private struct SettingsState: Equatable { } } -private func settingsEntries(presentationData: PresentationData, state: SettingsState, view: PeerView, proxySettings: ProxySettings, unreadTrendingStickerPacks: Int, archivedPacks: [ArchivedStickerPackItem]?) -> [SettingsEntry] { +private func settingsEntries(presentationData: PresentationData, state: SettingsState, view: PeerView, proxySettings: ProxySettings, unreadTrendingStickerPacks: Int, archivedPacks: [ArchivedStickerPackItem]?, hasPassport: Bool) -> [SettingsEntry] { var entries: [SettingsEntry] = [] if let peer = peerViewMainPeer(view) as? TelegramUser { @@ -383,8 +383,8 @@ private func settingsEntries(presentationData: PresentationData, state: Settings entries.append(.themes(presentationData.theme, SettingsItemIcons.appearance, presentationData.strings.ChatSettings_Appearance.lowercased().capitalized)) entries.append(.language(presentationData.theme, SettingsItemIcons.language, presentationData.strings.Settings_AppLanguage, presentationData.strings.Localization_LanguageName)) - if GlobalExperimentalSettings.enablePassport { - entries.append(.passport(presentationData.theme, SettingsItemIcons.secureId, "Telegram Passport", "")) + if hasPassport { + entries.append(.passport(presentationData.theme, SettingsItemIcons.secureId, presentationData.strings.Settings_Passport, "")) } entries.append(.askAQuestion(presentationData.theme, SettingsItemIcons.support, presentationData.strings.Settings_Support)) @@ -422,6 +422,9 @@ public func settingsController(account: Account, accountManager: AccountManager) let hiddenAvatarRepresentationDisposable = MetaDisposable() actionsDisposable.add(hiddenAvatarRepresentationDisposable) + let updatePassportDisposable = MetaDisposable() + actionsDisposable.add(updatePassportDisposable) + let currentAvatarMixin = Atomic(value: nil) var avatarGalleryTransitionArguments: ((AvatarGalleryEntry) -> GalleryTransitionArguments?)? @@ -624,8 +627,17 @@ public func settingsController(account: Account, accountManager: AccountManager) archivedPacks.set(.single(nil) |> then(archivedStickerPacks(account: account) |> map(Optional.init))) - let signal = combineLatest((account.applicationContext as! TelegramApplicationContext).presentationData, statePromise.get(), peerView, account.postbox.preferencesView(keys: [PreferencesKeys.proxySettings]), combineLatest(account.viewTracker.featuredStickerPacks(), archivedPacks.get())) - |> map { presentationData, state, view, preferences, featuredAndArchived -> (ItemListControllerState, (ItemListNodeState, SettingsEntry.ItemGenerationArguments)) in + let hasPassport = ValuePromise(false) + let updatePassport: () -> Void = { + updatePassportDisposable.set((twoStepAuthData(account.network) + |> deliverOnMainQueue).start(next: { value in + hasPassport.set(value.hasSecretValues) + })) + } + updatePassport() + + let signal = combineLatest(account.telegramApplicationContext.presentationData, statePromise.get(), peerView, account.postbox.preferencesView(keys: [PreferencesKeys.proxySettings]), combineLatest(account.viewTracker.featuredStickerPacks(), archivedPacks.get()), hasPassport.get()) + |> map { presentationData, state, view, preferences, featuredAndArchived, hasPassport -> (ItemListControllerState, (ItemListNodeState, SettingsEntry.ItemGenerationArguments)) in let proxySettings: ProxySettings if let value = preferences.values[PreferencesKeys.proxySettings] as? ProxySettings { proxySettings = value @@ -649,7 +661,7 @@ public func settingsController(account: Account, accountManager: AccountManager) } } - let listState = ItemListNodeState(entries: settingsEntries(presentationData: presentationData, state: state, view: view, proxySettings: proxySettings, unreadTrendingStickerPacks: unreadTrendingStickerPacks, archivedPacks: featuredAndArchived.1), style: .blocks) + let listState = ItemListNodeState(entries: settingsEntries(presentationData: presentationData, state: state, view: view, proxySettings: proxySettings, unreadTrendingStickerPacks: unreadTrendingStickerPacks, archivedPacks: featuredAndArchived.1, hasPassport: hasPassport), style: .blocks) return (controllerState, (listState, arguments)) } |> afterDisposed { @@ -700,6 +712,9 @@ public func settingsController(account: Account, accountManager: AccountManager) controller.tabBarItemDebugTapAction = { pushControllerImpl?(debugController(account: account, accountManager: accountManager)) } + controller.didAppear = { _ in + updatePassport() + } return controller } diff --git a/TelegramUI/TelegramInitializeLegacyComponents.swift b/TelegramUI/TelegramInitializeLegacyComponents.swift index e776147cae..6696dca29b 100644 --- a/TelegramUI/TelegramInitializeLegacyComponents.swift +++ b/TelegramUI/TelegramInitializeLegacyComponents.swift @@ -350,44 +350,56 @@ private final class LegacyComponentsGlobalsProviderImpl: NSObject, LegacyCompone } func navigationBarPallete() -> TGNavigationBarPallete! { + let theme: PresentationTheme if let account = legacyComponentsAccount { let presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 } - let theme = presentationData.theme.rootController.navigationBar - return TGNavigationBarPallete(backgroundColor: theme.backgroundColor, separatorColor: theme.separatorColor, titleColor: theme.primaryTextColor, tintColor: theme.accentTextColor) + theme = presentationData.theme } else { - return nil + theme = defaultPresentationTheme } + let barTheme = theme.rootController.navigationBar + return TGNavigationBarPallete(backgroundColor: barTheme.backgroundColor, separatorColor: barTheme.separatorColor, titleColor: barTheme.primaryTextColor, tintColor: barTheme.accentTextColor) } func menuSheetPallete() -> TGMenuSheetPallete! { + let theme: PresentationTheme if let account = legacyComponentsAccount { let presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 } - let theme = presentationData.theme.actionSheet - return TGMenuSheetPallete(dark: presentationData.theme.overallDarkAppearance, backgroundColor: theme.opaqueItemBackgroundColor, selectionColor: theme.opaqueItemHighlightedBackgroundColor, separatorColor: theme.opaqueItemSeparatorColor, accentColor: theme.controlAccentColor, destructiveColor: theme.destructiveActionTextColor, textColor: theme.primaryTextColor, secondaryTextColor: theme.secondaryTextColor, spinnerColor: theme.secondaryTextColor, badgeTextColor: theme.controlAccentColor, badgeImage: nil, cornersImage: generateStretchableFilledCircleImage(diameter: 11.0, color: nil, strokeColor: nil, strokeWidth: nil, backgroundColor: theme.opaqueItemBackgroundColor)) + theme = presentationData.theme } else { - return nil + theme = defaultPresentationTheme } + let sheetTheme = theme.actionSheet + + return TGMenuSheetPallete(dark: theme.overallDarkAppearance, backgroundColor: sheetTheme.opaqueItemBackgroundColor, selectionColor: sheetTheme.opaqueItemHighlightedBackgroundColor, separatorColor: sheetTheme.opaqueItemSeparatorColor, accentColor: sheetTheme.controlAccentColor, destructiveColor: sheetTheme.destructiveActionTextColor, textColor: sheetTheme.primaryTextColor, secondaryTextColor: sheetTheme.secondaryTextColor, spinnerColor: sheetTheme.secondaryTextColor, badgeTextColor: sheetTheme.controlAccentColor, badgeImage: nil, cornersImage: generateStretchableFilledCircleImage(diameter: 11.0, color: nil, strokeColor: nil, strokeWidth: nil, backgroundColor: sheetTheme.opaqueItemBackgroundColor)) } func mediaAssetsPallete() -> TGMediaAssetsPallete! { + let presentationTheme: PresentationTheme if let account = legacyComponentsAccount { let presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 } - let theme = presentationData.theme.list - let navigationBar = presentationData.theme.rootController.navigationBar - return TGMediaAssetsPallete(dark: presentationData.theme.overallDarkAppearance, backgroundColor: theme.plainBackgroundColor, selectionColor: theme.itemHighlightedBackgroundColor, separatorColor: theme.itemPlainSeparatorColor, textColor: theme.itemPrimaryTextColor, secondaryTextColor: theme.controlSecondaryColor, accentColor: theme.itemAccentColor, barBackgroundColor: navigationBar.backgroundColor, barSeparatorColor: navigationBar.separatorColor, navigationTitleColor: navigationBar.primaryTextColor, badge: generateStretchableFilledCircleImage(diameter: 22.0, color: navigationBar.accentTextColor), badgeTextColor: navigationBar.backgroundColor, sendIconImage: PresentationResourcesChat.chatInputPanelSendButtonImage(presentationData.theme), maybeAccentColor: navigationBar.accentTextColor) + presentationTheme = presentationData.theme } else { - return nil + presentationTheme = defaultPresentationTheme } + + let theme = presentationTheme.list + let navigationBar = presentationTheme.rootController.navigationBar + + return TGMediaAssetsPallete(dark: presentationTheme.overallDarkAppearance, backgroundColor: theme.plainBackgroundColor, selectionColor: theme.itemHighlightedBackgroundColor, separatorColor: theme.itemPlainSeparatorColor, textColor: theme.itemPrimaryTextColor, secondaryTextColor: theme.controlSecondaryColor, accentColor: theme.itemAccentColor, barBackgroundColor: navigationBar.backgroundColor, barSeparatorColor: navigationBar.separatorColor, navigationTitleColor: navigationBar.primaryTextColor, badge: generateStretchableFilledCircleImage(diameter: 22.0, color: navigationBar.accentTextColor), badgeTextColor: navigationBar.backgroundColor, sendIconImage: PresentationResourcesChat.chatInputPanelSendButtonImage(presentationTheme), maybeAccentColor: navigationBar.accentTextColor) } func checkButtonPallete() -> TGCheckButtonPallete! { + let presentationTheme: PresentationTheme if let account = legacyComponentsAccount { let presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 } - let theme = presentationData.theme - return TGCheckButtonPallete(defaultBackgroundColor: theme.chat.bubble.selectionControlFillColor, accentBackgroundColor: theme.chat.bubble.selectionControlFillColor, defaultBorderColor: theme.chat.bubble.selectionControlBorderColor, mediaBorderColor: theme.chat.bubble.selectionControlBorderColor, chatBorderColor: theme.chat.bubble.selectionControlBorderColor, check: theme.chat.bubble.selectionControlForegroundColor, blueColor: theme.chat.bubble.selectionControlFillColor, barBackgroundColor: theme.chat.bubble.selectionControlFillColor) + presentationTheme = presentationData.theme } else { - return nil + presentationTheme = defaultPresentationTheme } + + let theme = presentationTheme + return TGCheckButtonPallete(defaultBackgroundColor: theme.chat.bubble.selectionControlFillColor, accentBackgroundColor: theme.chat.bubble.selectionControlFillColor, defaultBorderColor: theme.chat.bubble.selectionControlBorderColor, mediaBorderColor: theme.chat.bubble.selectionControlBorderColor, chatBorderColor: theme.chat.bubble.selectionControlBorderColor, check: theme.chat.bubble.selectionControlForegroundColor, blueColor: theme.chat.bubble.selectionControlFillColor, barBackgroundColor: theme.chat.bubble.selectionControlFillColor) } } diff --git a/TelegramUI/ThemeAutoNightSettingsController.swift b/TelegramUI/ThemeAutoNightSettingsController.swift index d5319d4a58..faddbe2088 100644 --- a/TelegramUI/ThemeAutoNightSettingsController.swift +++ b/TelegramUI/ThemeAutoNightSettingsController.swift @@ -287,7 +287,7 @@ private func themeAutoNightSettingsControllerEntries(theme: PresentationTheme, s case let .automatic(_, _, sunset, sunrise, localizedName): entries.append(.timeBasedAutomaticLocationValue(theme, strings.AutoNightTheme_UpdateLocation, localizedName)) if sunset != 0 || sunrise != 0 { - entries.append(.settingInfo(theme, strings.AutoNightTheme_LocationHelp(stringForMessageTimestamp(timestamp: sunrise, timeFormat: timeFormat, local: false), stringForMessageTimestamp(timestamp: sunset, timeFormat: timeFormat, local: false)).0)) + entries.append(.settingInfo(theme, strings.AutoNightTheme_LocationHelp(stringForMessageTimestamp(timestamp: sunset, timeFormat: timeFormat, local: false), stringForMessageTimestamp(timestamp: sunrise, timeFormat: timeFormat, local: false)).0)) } case let .manual(fromSeconds, toSeconds): entries.append(.timeBasedManualFrom(theme, strings.AutoNightTheme_ScheduledFrom, stringForMessageTimestamp(timestamp: fromSeconds, timeFormat: timeFormat, local: false))) @@ -313,7 +313,7 @@ private func themeAutoNightSettingsControllerEntries(theme: PresentationTheme, s private func roundTimeToDay(_ timestamp: Int32) -> Int32 { let calendar = Calendar.current - let offset = TimeZone.current.secondsFromGMT(for: Date()) + let offset = 0//TimeZone.current.secondsFromGMT(for: Date()) let components = calendar.dateComponents([.hour, .minute, .second], from: Date(timeIntervalSince1970: Double(timestamp + Int32(offset)))) return Int32(components.hour! * 60 * 60 + components.minute! * 60 + components.second!) } @@ -324,7 +324,7 @@ private func areSettingsValid(_ settings: AutomaticThemeSwitchSetting) -> Bool { return true case let .timeBased(setting): switch setting { - case let .automatic(latitude, longitude, sunset, sunrise, _): + case let .automatic(latitude, longitude, _, _, _): if !latitude.isZero || !longitude.isZero { return true } else { @@ -391,7 +391,7 @@ public func themeAutoNightSettingsController(account: Account) -> ViewController updateSettings { settings in var settings = settings if case let .timeBased(setting) = settings.trigger, case .automatic = setting { - let calculator = EDSunriseSet(date: Date(), timezone: TimeZone(secondsFromGMT: 0), latitude: location.0, longitude: location.1)! + let calculator = EDSunriseSet(date: Date(), timezone: TimeZone.current, latitude: location.0, longitude: location.1)! let sunset = roundTimeToDay(Int32(calculator.sunset.timeIntervalSince1970)) let sunrise = roundTimeToDay(Int32(calculator.sunrise.timeIntervalSince1970)) diff --git a/TelegramUI/TwoStepVerificationEmptyItem.swift b/TelegramUI/TwoStepVerificationEmptyItem.swift new file mode 100644 index 0000000000..4d89132535 --- /dev/null +++ b/TelegramUI/TwoStepVerificationEmptyItem.swift @@ -0,0 +1,58 @@ +import Foundation +import AsyncDisplayKit +import Display + +final class TwoStepVerificationEmptyItem: ItemListControllerEmptyStateItem { + let theme: PresentationTheme + let strings: PresentationStrings + let setup: () -> Void + + init(theme: PresentationTheme, strings: PresentationStrings, setup: @escaping () -> Void) { + self.theme = theme + self.strings = strings + self.setup = setup + } + + func isEqual(to: ItemListControllerEmptyStateItem) -> Bool { + return to is TwoStepVerificationEmptyItem + } + + func node(current: ItemListControllerEmptyStateItemNode?) -> ItemListControllerEmptyStateItemNode { + if let current = current as? TwoStepVerificationEmptyItemNode { + current.item = self + return current + } else { + return TwoStepVerificationEmptyItemNode(item: self) + } + } +} + +final class TwoStepVerificationEmptyItemNode: ItemListControllerEmptyStateItemNode { + var item: TwoStepVerificationEmptyItem { + didSet { + if let (layout, navigationHeight) = self.validLayout { + self.updateLayout(layout: layout, navigationBarHeight: navigationHeight, transition: .immediate) + } + } + } + + + private var validLayout: (ContainerViewLayout, CGFloat)? + + init(item: TwoStepVerificationEmptyItem) { + self.item = item + + super.init() + + + } + + override func updateLayout(layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) { + self.validLayout = (layout, navigationBarHeight) + + var insets = layout.insets(options: [.statusBar]) + insets.top += navigationBarHeight + + + } +} diff --git a/TelegramUI/TwoStepVerificationPasswordEntryController.swift b/TelegramUI/TwoStepVerificationPasswordEntryController.swift index bb3cd3362d..20358d0865 100644 --- a/TelegramUI/TwoStepVerificationPasswordEntryController.swift +++ b/TelegramUI/TwoStepVerificationPasswordEntryController.swift @@ -229,7 +229,7 @@ private func twoStepVerificationPasswordEntryControllerEntries(presentationData: entries.append(.passwordEntryTitle(presentationData.theme, presentationData.strings.TwoStepAuth_SetupPasswordEnterPasswordNew)) entries.append(.passwordEntry(presentationData.theme, text)) case let .reentry(_, text): - entries.append(.passwordEntryTitle(presentationData.theme, presentationData.strings.TwoStepAuth_SetupPasswordEnterPasswordChange)) + entries.append(.passwordEntryTitle(presentationData.theme, presentationData.strings.TwoStepAuth_SetupPasswordConfirmPassword)) entries.append(.passwordEntry(presentationData.theme, text)) case let .hint(_, text): entries.append(.hintTitle(presentationData.theme, presentationData.strings.TwoStepAuth_SetupHint)) @@ -416,7 +416,15 @@ func twoStepVerificationPasswordEntryController(account: Account, mode: TwoStepV }) } - let controllerState = ItemListControllerState(theme: presentationData.theme, title: .text(presentationData.strings.TwoStepAuth_EnterPasswordTitle), leftNavigationButton: leftNavigationButton, rightNavigationButton: rightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: false) + let title: String + switch mode { + case .setup, .change: + title = presentationData.strings.TwoStepAuth_EnterPasswordTitle + case .setupEmail: + title = presentationData.strings.TwoStepAuth_EmailTitle + } + + let controllerState = ItemListControllerState(theme: presentationData.theme, title: .text(title), leftNavigationButton: leftNavigationButton, rightNavigationButton: rightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: false) let listState = ItemListNodeState(entries: twoStepVerificationPasswordEntryControllerEntries(presentationData: presentationData, state: state, mode: mode), style: .blocks, focusItemTag: TwoStepVerificationPasswordEntryTag.input, emptyStateItem: nil, animateChanges: false) return (controllerState, (listState, arguments)) @@ -431,6 +439,7 @@ func twoStepVerificationPasswordEntryController(account: Account, mode: TwoStepV } } dismissImpl = { [weak controller] in + controller?.view.endEditing(true) controller?.dismiss() } diff --git a/TelegramUI/TwoStepVerificationUnlockController.swift b/TelegramUI/TwoStepVerificationUnlockController.swift index e9af6dbf58..aae0b58a6a 100644 --- a/TelegramUI/TwoStepVerificationUnlockController.swift +++ b/TelegramUI/TwoStepVerificationUnlockController.swift @@ -6,14 +6,16 @@ import TelegramCore private final class TwoStepVerificationUnlockSettingsControllerArguments { let updatePasswordText: (String) -> Void + let checkPassword: () -> Void let openForgotPassword: () -> Void let openSetupPassword: () -> Void let openDisablePassword: () -> Void let openSetupEmail: () -> Void let openResetPendingEmail: () -> Void - init(updatePasswordText: @escaping (String) -> Void, openForgotPassword: @escaping () -> Void, openSetupPassword: @escaping () -> Void, openDisablePassword: @escaping () -> Void, openSetupEmail: @escaping () -> Void, openResetPendingEmail: @escaping () -> Void) { + init(updatePasswordText: @escaping (String) -> Void, checkPassword: @escaping () -> Void, openForgotPassword: @escaping () -> Void, openSetupPassword: @escaping () -> Void, openDisablePassword: @escaping () -> Void, openSetupEmail: @escaping () -> Void, openResetPendingEmail: @escaping () -> Void) { self.updatePasswordText = updatePasswordText + self.checkPassword = checkPassword self.openForgotPassword = openForgotPassword self.openSetupPassword = openSetupPassword self.openDisablePassword = openDisablePassword @@ -155,6 +157,7 @@ private enum TwoStepVerificationUnlockSettingsEntry: ItemListNodeEntry { return ItemListSingleLineInputItem(theme: theme, title: NSAttributedString(string: text, textColor: theme.list.itemPrimaryTextColor), text: value, placeholder: "", type: .password, spacing: 10.0, tag: TwoStepVerificationUnlockSettingsEntryTag.password, sectionId: self.section, textUpdated: { updatedText in arguments.updatePasswordText(updatedText) }, action: { + arguments.checkPassword() }) case let .passwordEntryInfo(theme, text): return ItemListTextItem(theme: theme, text: .markdown(text), sectionId: self.section, linkAction: { action in @@ -306,8 +309,46 @@ func twoStepVerificationUnlockSettingsController(account: Account, mode: TwoStep updateState { $0.withUpdatedPasswordText(updatedText) } + }, checkPassword: { + var wasChecking = false + var password: String? + updateState { state in + wasChecking = state.checking + password = state.passwordText + return state.withUpdatedChecking(true) + } + + if let password = password, !password.isEmpty, !wasChecking { + checkDisposable.set((requestTwoStepVerifiationSettings(network: account.network, password: password) |> deliverOnMainQueue).start(next: { settings in + updateState { + $0.withUpdatedChecking(false) + } + + replaceControllerImpl?(twoStepVerificationUnlockSettingsController(account: account, mode: .manage(password: password, email: settings.email, pendingEmailPattern: "", hasSecureValues: settings.secureSecret != nil))) + }, error: { error in + updateState { + $0.withUpdatedChecking(false) + } + + let presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 } + + let text: String + switch error { + case .limitExceeded: + text = presentationData.strings.LoginPassword_FloodError + case .invalidPassword: + text = presentationData.strings.LoginPassword_InvalidPasswordError + case .generic: + text = presentationData.strings.Login_UnknownError + } + + presentControllerImpl?(standardTextAlertController(theme: AlertControllerTheme(presentationTheme: presentationData.theme), title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), ViewControllerPresentationArguments(presentationAnimation: .modalSheet)) + })) + } }, openForgotPassword: { - setupDisposable.set((dataPromise.get() |> take(1) |> deliverOnMainQueue).start(next: { data in + setupDisposable.set((dataPromise.get() + |> take(1) + |> deliverOnMainQueue).start(next: { data in switch data { case let .access(configuration): if let configuration = configuration { @@ -318,17 +359,22 @@ func twoStepVerificationUnlockSettingsController(account: Account, mode: TwoStep updateState { $0.withUpdatedChecking(true) } - setupResultDisposable.set((requestTwoStepVerificationPasswordRecoveryCode(network: account.network) |> deliverOnMainQueue).start(next: { emailPattern in + setupResultDisposable.set((requestTwoStepVerificationPasswordRecoveryCode(network: account.network) + |> deliverOnMainQueue).start(next: { emailPattern in updateState { $0.withUpdatedChecking(false) } - let result = Promise() - let controller = twoStepVerificationResetController(account: account, emailPattern: emailPattern, result: result) + + var completionImpl: (() -> Void)? + let controller = resetPasswordController(account: account, emailPattern: emailPattern, completion: { + completionImpl?() + }) + completionImpl = { [weak controller] in + dataPromise.set(.single(TwoStepVerificationUnlockSettingsControllerData.access(configuration: TwoStepVerificationConfiguration.notSet(pendingEmailPattern: "")))) + controller?.view.endEditing(true) + controller?.dismiss() + } presentControllerImpl?(controller, ViewControllerPresentationArguments(presentationAnimation: .modalSheet)) - setupDisposable.set((result.get() |> take(1) |> deliverOnMainQueue).start(next: { [weak controller] _ in - dataPromise.set(.single(TwoStepVerificationUnlockSettingsControllerData.access(configuration: TwoStepVerificationConfiguration.notSet(pendingEmailPattern: "")))) - controller?.dismiss() - })) }, error: { _ in updateState { $0.withUpdatedChecking(false) @@ -347,13 +393,39 @@ func twoStepVerificationUnlockSettingsController(account: Account, mode: TwoStep } })) }, openSetupPassword: { - setupDisposable.set((dataPromise.get() |> take(1) |> deliverOnMainQueue).start(next: { data in + setupDisposable.set((dataPromise.get() + |> take(1) + |> deliverOnMainQueue).start(next: { data in switch data { case let .access(configuration): if let configuration = configuration { switch configuration { case .notSet: - let result = Promise() + var completionImpl: ((String, String, Bool) -> Void)? + var updatePatternImpl: ((String?) -> Void)? + let controller = createPasswordController(account: account, state: .setup(currentPassword: nil), completion: { password, hint, emailPattern in + completionImpl?(password, hint, emailPattern) + }, updatePasswordEmailConfirmation: { pattern in + updatePatternImpl?(pattern) + }, processPasswordEmailConfirmation: false) + presentControllerImpl?(controller, ViewControllerPresentationArguments(presentationAnimation: .modalSheet)) + completionImpl = { [weak controller] password, hint, hasRecovery in + dataPromise.set(.single(.manage(password: password, emailSet: hasRecovery, pendingEmailPattern: "", hasSecureValues: false))) + controller?.view.endEditing(true) + controller?.dismiss() + } + + updatePatternImpl = { [weak controller] pattern in + if let pattern = pattern { + dataPromise.set(.single(TwoStepVerificationUnlockSettingsControllerData.access(configuration: .notSet(pendingEmailPattern: pattern)))) + } else { + dataPromise.set(.single(TwoStepVerificationUnlockSettingsControllerData.access(configuration: .notSet(pendingEmailPattern: "")))) + } + controller?.view.endEditing(true) + controller?.dismiss() + } + + /*let result = Promise() let controller = twoStepVerificationPasswordEntryController(account: account, mode: .setup, result: result) presentControllerImpl?(controller, ViewControllerPresentationArguments(presentationAnimation: .modalSheet)) setupResultDisposable.set((result.get() |> take(1) |> deliverOnMainQueue).start(next: { [weak controller] updatedPassword in @@ -365,12 +437,36 @@ func twoStepVerificationUnlockSettingsController(account: Account, mode: TwoStep } controller?.dismiss() } - })) + }))*/ case .set: break } } - case let .manage(password, emailSet, pendingEmailPattern, hasSecureValues): + case let .manage(password, hasRecovery, pendingEmailPattern, hasSecureValues): + var completionImpl: ((String, String, Bool) -> Void)? + var updatePatternImpl: ((String?) -> Void)? + let controller = createPasswordController(account: account, state: .setup(currentPassword: password), completion: { password, hint, emailPattern in + completionImpl?(password, hint, emailPattern) + }, updatePasswordEmailConfirmation: { pattern in + updatePatternImpl?(pattern) + }, processPasswordEmailConfirmation: false) + presentControllerImpl?(controller, ViewControllerPresentationArguments(presentationAnimation: .modalSheet)) + completionImpl = { [weak controller] password, hint, _ in + dataPromise.set(.single(.manage(password: password, emailSet: hasRecovery, pendingEmailPattern: pendingEmailPattern, hasSecureValues: hasSecureValues))) + controller?.view.endEditing(true) + controller?.dismiss() + } + + updatePatternImpl = { [weak controller] pattern in + if let pattern = pattern { + dataPromise.set(.single(TwoStepVerificationUnlockSettingsControllerData.access(configuration: .notSet(pendingEmailPattern: pattern)))) + } else { + dataPromise.set(.single(TwoStepVerificationUnlockSettingsControllerData.access(configuration: .notSet(pendingEmailPattern: "")))) + } + controller?.view.endEditing(true) + controller?.dismiss() + } + /* let result = Promise() let controller = twoStepVerificationPasswordEntryController(account: account, mode: .change(current: password), result: result) presentControllerImpl?(controller, ViewControllerPresentationArguments(presentationAnimation: .modalSheet)) @@ -379,7 +475,7 @@ func twoStepVerificationUnlockSettingsController(account: Account, mode: TwoStep dataPromise.set(.single(TwoStepVerificationUnlockSettingsControllerData.manage(password: updatedPassword.password, emailSet: emailSet, pendingEmailPattern: pendingEmailPattern, hasSecureValues: hasSecureValues))) controller?.dismiss() } - })) + }))*/ } })) }, openDisablePassword: { @@ -485,41 +581,7 @@ func twoStepVerificationUnlockSettingsController(account: Account, mode: TwoStep break case let .set(_, _, _, hasSecureValues): rightNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Common_Next), style: .bold, enabled: true, action: { - var wasChecking = false - var password: String? - updateState { state in - wasChecking = state.checking - password = state.passwordText - return state.withUpdatedChecking(true) - } - - if let password = password, !wasChecking { - checkDisposable.set((requestTwoStepVerifiationSettings(network: account.network, password: password) |> deliverOnMainQueue).start(next: { settings in - updateState { - $0.withUpdatedChecking(false) - } - - replaceControllerImpl?(twoStepVerificationUnlockSettingsController(account: account, mode: .manage(password: password, email: settings.email, pendingEmailPattern: "", hasSecureValues: hasSecureValues))) - }, error: { error in - updateState { - $0.withUpdatedChecking(false) - } - - let presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 } - - let text: String - switch error { - case .limitExceeded: - text = presentationData.strings.LoginPassword_FloodError - case .invalidPassword: - text = presentationData.strings.LoginPassword_InvalidPasswordError - case .generic: - text = presentationData.strings.Login_UnknownError - } - - presentControllerImpl?(standardTextAlertController(theme: AlertControllerTheme(presentationTheme: presentationData.theme), title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), ViewControllerPresentationArguments(presentationAnimation: .modalSheet)) - })) - } + arguments.checkPassword() }) } } @@ -566,7 +628,10 @@ func twoStepVerificationUnlockSettingsController(account: Account, mode: TwoStep resultItemNode.focus() } } - controller.didAppear = { + controller.didAppear = { firstTime in + if !firstTime { + return + } initialFocusImpl?() } diff --git a/TelegramUI/UrlHandling.swift b/TelegramUI/UrlHandling.swift index 03383c42e2..16fa69754d 100644 --- a/TelegramUI/UrlHandling.swift +++ b/TelegramUI/UrlHandling.swift @@ -139,6 +139,28 @@ private func resolveInternalUrl(account: Account, url: ParsedInternalUrl) -> Sig } } +func parseProxyUrl(_ url: String) -> (host: String, port: Int32, username: String?, password: String?, secret: Data?)? { + let schemes = ["http://", "https://", ""] + let baseTelegramMePaths = ["telegram.me", "t.me"] + for basePath in baseTelegramMePaths { + for scheme in schemes { + let basePrefix = scheme + basePath + "/" + if url.lowercased().hasPrefix(basePrefix) { + if let internalUrl = parseInternalUrl(query: String(url[basePrefix.endIndex...])), case let .proxy(proxy) = internalUrl { + return (proxy.host, proxy.port, proxy.username, proxy.password, proxy.secret) + } + } + } + } + if let parsedUrl = URL(string: url), parsedUrl.scheme == "tg", let host = parsedUrl.host, let query = parsedUrl.query { + if let internalUrl = parseInternalUrl(query: host + "?" + query), case let .proxy(proxy) = internalUrl { + return (proxy.host, proxy.port, proxy.username, proxy.password, proxy.secret) + } + } + + return nil +} + func resolveUrl(account: Account, url: String) -> Signal { let schemes = ["http://", "https://", ""] let baseTelegramMePaths = ["telegram.me", "t.me"] @@ -148,13 +170,13 @@ func resolveUrl(account: Account, url: String) -> Signal { if url.lowercased().hasPrefix(basePrefix) { if let internalUrl = parseInternalUrl(query: String(url[basePrefix.endIndex...])) { return resolveInternalUrl(account: account, url: internalUrl) - |> map { resolved -> ResolvedUrl in - if let resolved = resolved { - return resolved - } else { - return .externalUrl(url) - } + |> map { resolved -> ResolvedUrl in + if let resolved = resolved { + return resolved + } else { + return .externalUrl(url) } + } } else { return .single(.externalUrl(url)) } diff --git a/TelegramUI/UserInfoController.swift b/TelegramUI/UserInfoController.swift index 1bbc6ffa22..c39837bf61 100644 --- a/TelegramUI/UserInfoController.swift +++ b/TelegramUI/UserInfoController.swift @@ -1270,8 +1270,8 @@ public func userInfoController(account: Account, peerId: PeerId) -> ViewControll } } - controller.didAppear = { [weak controller] in - guard let controller = controller else { + controller.didAppear = { [weak controller] firstTime in + guard let controller = controller, firstTime else { return } diff --git a/TelegramUI/UsernameSetupController.swift b/TelegramUI/UsernameSetupController.swift index 4d987d0ffa..25169eb0c2 100644 --- a/TelegramUI/UsernameSetupController.swift +++ b/TelegramUI/UsernameSetupController.swift @@ -8,10 +8,12 @@ private final class UsernameSetupControllerArguments { let account: Account let updatePublicLinkText: (String?, String) -> Void + let shareLink: () -> Void - init(account: Account, updatePublicLinkText: @escaping (String?, String) -> Void) { + init(account: Account, updatePublicLinkText: @escaping (String?, String) -> Void, shareLink: @escaping () -> Void) { self.account = account self.updatePublicLinkText = updatePublicLinkText + self.shareLink = shareLink } } @@ -20,7 +22,7 @@ private enum UsernameSetupSection: Int32 { } private enum UsernameSetupEntry: ItemListNodeEntry { - case editablePublicLink(PresentationTheme, String?, String) + case editablePublicLink(PresentationTheme, String, String?, String) case publicLinkStatus(PresentationTheme, String, AddressNameValidationStatus, String) case publicLinkInfo(PresentationTheme, String) @@ -44,8 +46,8 @@ private enum UsernameSetupEntry: ItemListNodeEntry { static func ==(lhs: UsernameSetupEntry, rhs: UsernameSetupEntry) -> Bool { switch lhs { - case let .editablePublicLink(lhsTheme, lhsCurrentText, lhsText): - if case let .editablePublicLink(rhsTheme, rhsCurrentText, rhsText) = rhs, lhsTheme === rhsTheme, lhsCurrentText == rhsCurrentText, lhsText == rhsText { + case let .editablePublicLink(lhsTheme, lhsPrefix, lhsCurrentText, lhsText): + if case let .editablePublicLink(rhsTheme, rhsPrefix, rhsCurrentText, rhsText) = rhs, lhsTheme === rhsTheme, lhsPrefix == rhsPrefix, lhsCurrentText == rhsCurrentText, lhsText == rhsText { return true } else { return false @@ -71,14 +73,18 @@ private enum UsernameSetupEntry: ItemListNodeEntry { func item(_ arguments: UsernameSetupControllerArguments) -> ListViewItem { switch self { - case let .editablePublicLink(theme, currentText, text): - return ItemListSingleLineInputItem(theme: theme, title: NSAttributedString(string: "t.me/", textColor: theme.list.itemPrimaryTextColor), text: text, placeholder: "", type: .username, sectionId: self.section, textUpdated: { updatedText in + case let .editablePublicLink(theme, prefix, currentText, text): + return ItemListSingleLineInputItem(theme: theme, title: NSAttributedString(string: prefix, textColor: theme.list.itemPrimaryTextColor), text: text, placeholder: "", type: .username, spacing: 10.0, sectionId: self.section, textUpdated: { updatedText in arguments.updatePublicLinkText(currentText, updatedText) }, action: { }) case let .publicLinkInfo(theme, text): - return ItemListTextItem(theme: theme, text: .markdown(text), sectionId: self.section) + return ItemListTextItem(theme: theme, text: .markdown(text), sectionId: self.section, linkAction: { action in + if case .tap = action { + arguments.shareLink() + } + }) case let .publicLinkStatus(theme, _, status, text): var displayActivity = false let string: NSAttributedString @@ -160,7 +166,7 @@ private func usernameSetupControllerEntries(presentationData: PresentationData, } } - entries.append(.editablePublicLink(presentationData.theme, peer.addressName, currentAddressName)) + entries.append(.editablePublicLink(presentationData.theme, presentationData.strings.Username_Title, peer.addressName, currentAddressName)) if let status = state.addressNameValidationStatus { let statusText: String switch status { @@ -187,7 +193,12 @@ private func usernameSetupControllerEntries(presentationData: PresentationData, } entries.append(.publicLinkStatus(presentationData.theme, currentAddressName, status, statusText)) } - entries.append(.publicLinkInfo(presentationData.theme, presentationData.strings.Username_Help)) + + var infoText = presentationData.strings.Username_Help + infoText += "\n\n" + let hintText = presentationData.strings.Username_LinkHint(currentAddressName.replacingOccurrences(of: "[", with: "").replacingOccurrences(of: "]", with: "")).0.replacingOccurrences(of: "]", with: "]()") + infoText += hintText + entries.append(.publicLinkInfo(presentationData.theme, infoText)) } return entries @@ -201,6 +212,7 @@ public func usernameSetupController(account: Account) -> ViewController { } var dismissImpl: (() -> Void)? + var presentControllerImpl: ((ViewController, Any?) -> Void)? let actionsDisposable = DisposableSet() @@ -233,10 +245,25 @@ public func usernameSetupController(account: Account) -> ViewController { } })) } + }, shareLink: { + let _ = (account.postbox.loadedPeerWithId(account.peerId) + |> take(1) + |> deliverOnMainQueue).start(next: { peer in + var currentAddressName: String = peer.addressName ?? "" + updateState { state in + if let current = state.editingPublicLinkText { + currentAddressName = current + } + return state + } + if !currentAddressName.isEmpty { + presentControllerImpl?(ShareController(account: account, subject: .url("https://t.me/\(currentAddressName)")), nil) + } + }) }) let peerView = account.viewTracker.peerView(account.peerId) - |> deliverOnMainQueue + |> deliverOnMainQueue let signal = combineLatest((account.applicationContext as! TelegramApplicationContext).presentationData, statePromise.get() |> deliverOnMainQueue, peerView) |> map { presentationData, state, view -> (ItemListControllerState, (ItemListNodeState, UsernameSetupEntry.ItemGenerationArguments)) in @@ -306,6 +333,9 @@ public func usernameSetupController(account: Account) -> ViewController { controller?.view.endEditing(true) controller?.dismiss() } + presentControllerImpl = { [weak controller] c, a in + controller?.present(c, in: .window(.root), with: a) + } return controller } diff --git a/third-party/RMIntro/core/animations.c b/third-party/RMIntro/core/animations.c index 0f17afdb59..f38708d9f9 100644 --- a/third-party/RMIntro/core/animations.c +++ b/third-party/RMIntro/core/animations.c @@ -2090,7 +2090,7 @@ void on_draw_frame() { telegram_sphere.params.alpha = t(0, 1, 0, duration_const*.8, Linear); - scale = 1.01; + scale = 1.005; telegram_sphere.params.scale = xyzMake(scale, scale, 1); draw_textured_shape(&telegram_sphere, main_matrix, NORMAL); diff --git a/third-party/RMIntro/platform/ios/RMIntroViewController.m b/third-party/RMIntro/platform/ios/RMIntroViewController.m index 3355012ff4..7e089972c8 100644 --- a/third-party/RMIntro/platform/ios/RMIntroViewController.m +++ b/third-party/RMIntro/platform/ios/RMIntroViewController.m @@ -20,9 +20,6 @@ #import #import -#define TGLog NSLog -#define TGLocalized(x) NSLocalizedString(x, @"") - typedef enum { Inch35 = 0, Inch4 = 1, @@ -94,6 +91,7 @@ static void TGDispatchOnMainThread(dispatch_block_t block) { TGSuggestedLocalization *_alternativeLocalizationInfo; SVariable *_alternativeLocalization; + NSDictionary *_englishStrings; } @end @@ -116,8 +114,40 @@ static void TGDispatchOnMainThread(dispatch_block_t block) { self.automaticallyAdjustsScrollViewInsets = false; - _headlines = @[ TGLocalized(@"Tour.Title1"), TGLocalized(@"Tour.Title2"), TGLocalized(@"Tour.Title6"), TGLocalized(@"Tour.Title3"), TGLocalized(@"Tour.Title4"), TGLocalized(@"Tour.Title5")]; - _descriptions = @[TGLocalized(@"Tour.Text1"), TGLocalized(@"Tour.Text2"), TGLocalized(@"Tour.Text6"), TGLocalized(@"Tour.Text3"), TGLocalized(@"Tour.Text4"), TGLocalized(@"Tour.Text5")]; + NSArray *stringKeys = @[ + @"Tour.Title1", + @"Tour.Title2", + @"Tour.Title3", + @"Tour.Title4", + @"Tour.Title5", + @"Tour.Title6", + @"Tour.Text1", + @"Tour.Text2", + @"Tour.Text3", + @"Tour.Text4", + @"Tour.Text5", + @"Tour.Text6", + @"Tour.StartButton" + ]; + + NSMutableDictionary *englishStrings = [[NSMutableDictionary alloc] init]; + NSBundle *bundle = [NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:@"en" ofType:@"lproj"]]; + for (NSString *key in stringKeys) { + if (bundle != nil) { + NSString *value = [bundle localizedStringForKey:key value:key table:nil]; + if (value != nil) { + englishStrings[key] = value; + } else { + englishStrings[key] = key; + } + } else { + englishStrings[key] = key; + } + } + _englishStrings = englishStrings; + + _headlines = @[ _englishStrings[@"Tour.Title1"], _englishStrings[@"Tour.Title2"], _englishStrings[@"Tour.Title6"], _englishStrings[@"Tour.Title3"], _englishStrings[@"Tour.Title4"], _englishStrings[@"Tour.Title5"]]; + _descriptions = @[_englishStrings[@"Tour.Text1"], _englishStrings[@"Tour.Text2"], _englishStrings[@"Tour.Text6"], _englishStrings[@"Tour.Text3"], _englishStrings[@"Tour.Text4"], _englishStrings[@"Tour.Text5"]]; __weak RMIntroViewController *weakSelf = self; _didEnterBackgroundObserver = [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationDidEnterBackgroundNotification object:nil queue:nil usingBlock:^(__unused NSNotification *notification) @@ -288,7 +318,7 @@ static void TGDispatchOnMainThread(dispatch_block_t block) { _startButton = [[UIButton alloc] init]; _startButton.adjustsImageWhenDisabled = false; - [_startButton setTitle:TGLocalized(@"Tour.StartButton") forState:UIControlStateNormal]; + [_startButton setTitle:_englishStrings[@"Tour.StartButton"] forState:UIControlStateNormal]; [_startButton.titleLabel setFont:TGMediumSystemFontOfSize(20.0f)]; [_startButton setTitleColor:_backgroundColor forState:UIControlStateNormal]; static UIImage *buttonBackgroundImage = nil; diff --git a/third-party/RMIntro/platform/ios/texture_helper.m b/third-party/RMIntro/platform/ios/texture_helper.m index 9acebf6e2c..6377f8f93e 100644 --- a/third-party/RMIntro/platform/ios/texture_helper.m +++ b/third-party/RMIntro/platform/ios/texture_helper.m @@ -15,7 +15,7 @@ GLuint setup_texture(NSString *fileName) CGImageRef spriteImage = [[UIImage imageNamed:fileName] CGImage]; if (!spriteImage) { NSLog(@"Failed to load image %@", fileName); - exit(1); + return -1; } @@ -28,6 +28,10 @@ GLuint setup_texture(NSString *fileName) CGContextRef spriteContext = CGBitmapContextCreate(spriteData, width, height, 8, width*4, CGImageGetColorSpace(spriteImage), (CGBitmapInfo)kCGImageAlphaPremultipliedLast); // 3 + if ([fileName isEqualToString:@"telegram_sphere.png"]) { + CGContextSetFillColorWithColor(spriteContext, [UIColor whiteColor].CGColor); + CGContextFillRect(spriteContext, CGRectMake(0, 0, width, height)); + } CGContextDrawImage(spriteContext, CGRectMake(0, 0, width, height), spriteImage); CGContextRelease(spriteContext);